@dou-ui/dashboard 0.0.0-stage → 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/chart/chart-settings.js +6 -0
- package/dist/chart/chart-settings.js.map +1 -0
- package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js +122 -0
- package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/chart/chart.js +6 -0
- package/dist/chart/chart.js.map +1 -0
- package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js +99 -0
- package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/chart/index.js +33 -0
- package/dist/chart/index.js.map +1 -0
- package/dist/collaboration/index.js +281 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/order.js +88 -0
- package/dist/collaboration/order.js.map +1 -0
- package/dist/core/document.js +128 -0
- package/dist/core/document.js.map +1 -0
- package/dist/core/history.js +66 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/transaction.js +218 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/dashboard/dashboard.js +6 -0
- package/dist/dashboard/dashboard.js.map +1 -0
- package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js +1072 -0
- package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/export.js +77 -0
- package/dist/dashboard/export.js.map +1 -0
- package/dist/dashboard/filter-bar.js +6 -0
- package/dist/dashboard/filter-bar.js.map +1 -0
- package/dist/dashboard/filter-bar.vue_vue_type_script_setup_true_lang.js +150 -0
- package/dist/dashboard/filter-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/frame-context.js +5 -0
- package/dist/dashboard/frame-context.js.map +1 -0
- package/dist/dashboard/observers.js +48 -0
- package/dist/dashboard/observers.js.map +1 -0
- package/dist/dashboard/palette.js +6 -0
- package/dist/dashboard/palette.js.map +1 -0
- package/dist/dashboard/palette.vue_vue_type_script_setup_true_lang.js +54 -0
- package/dist/dashboard/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/widget-body.js +6 -0
- package/dist/dashboard/widget-body.js.map +1 -0
- package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js +96 -0
- package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/widget-frame.js +6 -0
- package/dist/dashboard/widget-frame.js.map +1 -0
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +300 -0
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/widget-settings.js +6 -0
- package/dist/dashboard/widget-settings.js.map +1 -0
- package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js +36 -0
- package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/data/context.js +5 -0
- package/dist/data/context.js.map +1 -0
- package/dist/data/filters.js +31 -0
- package/dist/data/filters.js.map +1 -0
- package/dist/data/store.js +214 -0
- package/dist/data/store.js.map +1 -0
- package/dist/grid/grid-handle.js +6 -0
- package/dist/grid/grid-handle.js.map +1 -0
- package/dist/grid/grid-handle.vue_vue_type_script_setup_true_lang.js +21 -0
- package/dist/grid/grid-handle.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/grid/grid-item.js +80 -0
- package/dist/grid/grid-item.js.map +1 -0
- package/dist/grid/grid-layout.js +6 -0
- package/dist/grid/grid-layout.js.map +1 -0
- package/dist/grid/grid-layout.vue_vue_type_script_setup_true_lang.js +767 -0
- package/dist/grid/grid-layout.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/grid/tiers.js +31 -0
- package/dist/grid/tiers.js.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/engine.js +284 -0
- package/dist/layout/engine.js.map +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/locale.js +245 -0
- package/dist/locale.js.map +1 -0
- package/dist/pivot/index.js +47 -0
- package/dist/pivot/index.js.map +1 -0
- package/dist/pivot/pivot-settings.js +6 -0
- package/dist/pivot/pivot-settings.js.map +1 -0
- package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js +64 -0
- package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/pivot/pivot.js +6 -0
- package/dist/pivot/pivot.js.map +1 -0
- package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js +76 -0
- package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +12 -0
- package/dist/types/chart/chart-settings.vue.d.ts +11 -0
- package/dist/types/chart/chart.vue.d.ts +3 -0
- package/dist/types/chart/index.d.ts +9 -0
- package/dist/types/chart/types.d.ts +23 -0
- package/dist/types/collaboration/index.d.ts +53 -0
- package/dist/types/collaboration/order.d.ts +20 -0
- package/dist/types/core/collaboration.d.ts +51 -0
- package/dist/types/core/document.d.ts +35 -0
- package/dist/types/core/history.d.ts +15 -0
- package/dist/types/core/transaction.d.ts +86 -0
- package/dist/types/core/types.d.ts +27 -0
- package/dist/types/dashboard/dashboard.vue.d.ts +33 -0
- package/dist/types/dashboard/export.d.ts +11 -0
- package/dist/types/dashboard/filter-bar.vue.d.ts +19 -0
- package/dist/types/dashboard/frame-context.d.ts +54 -0
- package/dist/types/dashboard/observers.d.ts +15 -0
- package/dist/types/dashboard/palette.vue.d.ts +20 -0
- package/dist/types/dashboard/types.d.ts +190 -0
- package/dist/types/dashboard/widget-body.vue.d.ts +19 -0
- package/dist/types/dashboard/widget-frame.vue.d.ts +6 -0
- package/dist/types/dashboard/widget-settings.vue.d.ts +16 -0
- package/dist/types/data/context.d.ts +18 -0
- package/dist/types/data/filters.d.ts +9 -0
- package/dist/types/data/store.d.ts +48 -0
- package/dist/types/data/types.d.ts +67 -0
- package/dist/types/grid/grid-handle.vue.d.ts +18 -0
- package/dist/types/grid/grid-item.d.ts +78 -0
- package/dist/types/grid/grid-layout.vue.d.ts +46 -0
- package/dist/types/grid/tiers.d.ts +12 -0
- package/dist/types/grid/types.d.ts +113 -0
- package/dist/types/index.d.ts +295 -0
- package/dist/types/layout/engine.d.ts +50 -0
- package/dist/types/layout/index.d.ts +2 -0
- package/dist/types/layout/types.d.ts +39 -0
- package/dist/types/locale.d.ts +117 -0
- package/dist/types/pivot/index.d.ts +14 -0
- package/dist/types/pivot/pivot-settings.vue.d.ts +16 -0
- package/dist/types/pivot/pivot.vue.d.ts +7 -0
- package/dist/types/pivot/types.d.ts +11 -0
- package/dist/types/widget/context.d.ts +91 -0
- package/dist/types/widget/define.d.ts +50 -0
- package/dist/types/widgets/field-select.vue.d.ts +18 -0
- package/dist/types/widgets/index.d.ts +15 -0
- package/dist/types/widgets/settings-field.vue.d.ts +17 -0
- package/dist/types/widgets/shared.d.ts +20 -0
- package/dist/types/widgets/source-field.vue.d.ts +15 -0
- package/dist/types/widgets/stat-settings.vue.d.ts +11 -0
- package/dist/types/widgets/stat.vue.d.ts +3 -0
- package/dist/types/widgets/table-settings.vue.d.ts +11 -0
- package/dist/types/widgets/table.vue.d.ts +3 -0
- package/dist/types/widgets/text-settings.vue.d.ts +11 -0
- package/dist/types/widgets/text.vue.d.ts +3 -0
- package/dist/types/widgets/types.d.ts +38 -0
- package/dist/widget/context.js +88 -0
- package/dist/widget/context.js.map +1 -0
- package/dist/widget/define.js +32 -0
- package/dist/widget/define.js.map +1 -0
- package/dist/widgets/field-select.js +6 -0
- package/dist/widgets/field-select.js.map +1 -0
- package/dist/widgets/field-select.vue_vue_type_script_setup_true_lang.js +54 -0
- package/dist/widgets/field-select.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/index.js +74 -0
- package/dist/widgets/index.js.map +1 -0
- package/dist/widgets/settings-field.js +6 -0
- package/dist/widgets/settings-field.js.map +1 -0
- package/dist/widgets/settings-field.vue_vue_type_script_setup_true_lang.js +28 -0
- package/dist/widgets/settings-field.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/shared.js +68 -0
- package/dist/widgets/shared.js.map +1 -0
- package/dist/widgets/source-field.js +6 -0
- package/dist/widgets/source-field.js.map +1 -0
- package/dist/widgets/source-field.vue_vue_type_script_setup_true_lang.js +47 -0
- package/dist/widgets/source-field.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/stat-settings.js +6 -0
- package/dist/widgets/stat-settings.js.map +1 -0
- package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js +107 -0
- package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/stat.js +6 -0
- package/dist/widgets/stat.js.map +1 -0
- package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js +72 -0
- package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/table-settings.js +6 -0
- package/dist/widgets/table-settings.js.map +1 -0
- package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js +90 -0
- package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/table.js +6 -0
- package/dist/widgets/table.js.map +1 -0
- package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js +91 -0
- package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/text-settings.js +6 -0
- package/dist/widgets/text-settings.js.map +1 -0
- package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js +63 -0
- package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/widgets/text.js +6 -0
- package/dist/widgets/text.js.map +1 -0
- package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js +16 -0
- package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/package.json +98 -4
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
import { deriveLayout, findPlace, fitItem, layoutHeight, moveItem, moveItemBy, normalizeLayout, resizeItem, resizeItemBy } from "../layout/engine.js";
|
|
2
|
+
import { format, useDashboardMessages } from "../locale.js";
|
|
3
|
+
import grid_item_default, { gridItemKey } from "./grid-item.js";
|
|
4
|
+
import { DEFAULT_BREAKPOINTS, DEFAULT_COLUMNS, gridTiers } from "./tiers.js";
|
|
5
|
+
import { holdPointer, useElementSize } from "dou-ui";
|
|
6
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, defineComponent, mergeModels, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, provide, ref, renderList, renderSlot, shallowRef, toDisplayString, unref, useId, useModel, useSlots, watch } from "vue";
|
|
7
|
+
// src/grid/grid-layout.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
+
var _hoisted_1 = ["role", "aria-label"];
|
|
9
|
+
var _hoisted_2 = {
|
|
10
|
+
key: 2,
|
|
11
|
+
class: "dou-grid-layout__live",
|
|
12
|
+
"aria-live": "assertive",
|
|
13
|
+
"aria-atomic": "true"
|
|
14
|
+
};
|
|
15
|
+
var DRAG_DISTANCE = 4;
|
|
16
|
+
/** How long a finger rests on an item before it is picked up, in ms. */
|
|
17
|
+
var HOLD_DELAY = 400;
|
|
18
|
+
/** How far a finger may move while resting, in px; further is a scroll. */
|
|
19
|
+
var HOLD_SLOP = 8;
|
|
20
|
+
/** The band along the top and bottom of the scrolling area that scrolls it during a drag, in px. */
|
|
21
|
+
var EDGE = 56;
|
|
22
|
+
/** The fastest that band scrolls, in px per frame. */
|
|
23
|
+
var EDGE_SPEED = 20;
|
|
24
|
+
/** How long items keep their transition after a drop, in ms (a little over the motion token). */
|
|
25
|
+
var SETTLE = 320;
|
|
26
|
+
var NO_DRAG = "input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [data-dou-nodrag]";
|
|
27
|
+
var grid_layout_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
28
|
+
name: "DouGridLayout",
|
|
29
|
+
__name: "grid-layout",
|
|
30
|
+
props: /*@__PURE__*/ mergeModels({
|
|
31
|
+
columns: { default: () => DEFAULT_COLUMNS },
|
|
32
|
+
breakpoints: { default: () => DEFAULT_BREAKPOINTS },
|
|
33
|
+
rowHeight: { default: 80 },
|
|
34
|
+
gap: { default: 16 },
|
|
35
|
+
compact: {
|
|
36
|
+
type: [String, Boolean],
|
|
37
|
+
default: "vertical"
|
|
38
|
+
},
|
|
39
|
+
editable: { type: Boolean },
|
|
40
|
+
handle: { type: Boolean },
|
|
41
|
+
resize: {
|
|
42
|
+
type: [Boolean, Array],
|
|
43
|
+
default: true
|
|
44
|
+
},
|
|
45
|
+
itemLabel: {},
|
|
46
|
+
label: {},
|
|
47
|
+
messages: {}
|
|
48
|
+
}, {
|
|
49
|
+
"modelValue": { default: () => [] },
|
|
50
|
+
"modelModifiers": {},
|
|
51
|
+
"layouts": { default: () => ({}) },
|
|
52
|
+
"layoutsModifiers": {}
|
|
53
|
+
}),
|
|
54
|
+
emits: /*@__PURE__*/ mergeModels([
|
|
55
|
+
"change",
|
|
56
|
+
"dragStart",
|
|
57
|
+
"dragEnd",
|
|
58
|
+
"drop",
|
|
59
|
+
"breakpointChange"
|
|
60
|
+
], ["update:modelValue", "update:layouts"]),
|
|
61
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
62
|
+
const props = __props;
|
|
63
|
+
const emit = __emit;
|
|
64
|
+
const model = useModel(__props, "modelValue");
|
|
65
|
+
const layouts = useModel(__props, "layouts");
|
|
66
|
+
const messages = useDashboardMessages(() => props.messages);
|
|
67
|
+
const slots = useSlots();
|
|
68
|
+
const hintId = `${useId()}-hint`;
|
|
69
|
+
provide(gridItemKey, {
|
|
70
|
+
slots,
|
|
71
|
+
hintId,
|
|
72
|
+
resizeLabel: () => messages.value.resize
|
|
73
|
+
});
|
|
74
|
+
/** How far a mouse moves before a press becomes a move, in px. */
|
|
75
|
+
const root = ref();
|
|
76
|
+
const tiers = computed(() => gridTiers(props.columns, props.breakpoints));
|
|
77
|
+
const { width: gridWidth } = useElementSize(root);
|
|
78
|
+
const tier = computed(() => {
|
|
79
|
+
const list = tiers.value;
|
|
80
|
+
if (!gridWidth.value) return list[0];
|
|
81
|
+
return list.find((t) => gridWidth.value >= t.min) ?? list.at(-1);
|
|
82
|
+
});
|
|
83
|
+
/** The widest breakpoint: the one `v-model` holds. */
|
|
84
|
+
const isMain = computed(() => tier.value === tiers.value[0]);
|
|
85
|
+
const optionsOf = (t) => ({
|
|
86
|
+
columns: Math.max(1, Math.round(t.columns)),
|
|
87
|
+
compact: props.compact
|
|
88
|
+
});
|
|
89
|
+
const options = computed(() => optionsOf(tier.value));
|
|
90
|
+
const mainLayout = computed(() => normalizeLayout(model.value, optionsOf(tiers.value[0])));
|
|
91
|
+
const settledRaw = computed(() => {
|
|
92
|
+
if (isMain.value) return mainLayout.value;
|
|
93
|
+
const main = mainLayout.value;
|
|
94
|
+
const derived = deriveLayout(main, optionsOf(tiers.value[0]).columns, options.value);
|
|
95
|
+
const saved = layouts.value[tier.value.name];
|
|
96
|
+
if (!saved?.length) return derived;
|
|
97
|
+
const places = new Map(saved.map((place) => [place.id, place]));
|
|
98
|
+
return normalizeLayout(main.map((item, i) => {
|
|
99
|
+
const place = places.get(item.id);
|
|
100
|
+
return place ? {
|
|
101
|
+
...item,
|
|
102
|
+
x: place.x,
|
|
103
|
+
y: place.y,
|
|
104
|
+
w: place.w,
|
|
105
|
+
h: place.h
|
|
106
|
+
} : derived[i];
|
|
107
|
+
}), options.value);
|
|
108
|
+
});
|
|
109
|
+
/**
|
|
110
|
+
* The items drawn last time are reused where nothing about them changed, so
|
|
111
|
+
* a change to one item draws only that one again, even when the layout had
|
|
112
|
+
* to be worked out anew (e.g. from a document that wasn't compacted).
|
|
113
|
+
*/
|
|
114
|
+
let drawnById = /* @__PURE__ */ new Map();
|
|
115
|
+
const ITEM_KEYS = [
|
|
116
|
+
"x",
|
|
117
|
+
"y",
|
|
118
|
+
"w",
|
|
119
|
+
"h",
|
|
120
|
+
"minW",
|
|
121
|
+
"maxW",
|
|
122
|
+
"minH",
|
|
123
|
+
"maxH",
|
|
124
|
+
"locked"
|
|
125
|
+
];
|
|
126
|
+
const settled = computed(() => {
|
|
127
|
+
const next = /* @__PURE__ */ new Map();
|
|
128
|
+
const list = settledRaw.value.map((item) => {
|
|
129
|
+
const old = drawnById.get(item.id);
|
|
130
|
+
const keep = old && ITEM_KEYS.every((key) => old[key] === item[key]) ? old : item;
|
|
131
|
+
next.set(item.id, keep);
|
|
132
|
+
return keep;
|
|
133
|
+
});
|
|
134
|
+
drawnById = next;
|
|
135
|
+
return list;
|
|
136
|
+
});
|
|
137
|
+
watch(() => tier.value.name, (name, old) => old !== void 0 && emit("breakpointChange", name));
|
|
138
|
+
/** The layout while a move or resize is under way; shown instead of `settled`. */
|
|
139
|
+
const preview = shallowRef(null);
|
|
140
|
+
const layout = computed(() => preview.value ?? settled.value);
|
|
141
|
+
const gaps = computed(() => Array.isArray(props.gap) ? props.gap : [props.gap, props.gap]);
|
|
142
|
+
const handles = computed(() => {
|
|
143
|
+
const list = props.resize === false ? [] : props.resize === true ? [
|
|
144
|
+
"e",
|
|
145
|
+
"s",
|
|
146
|
+
"se"
|
|
147
|
+
] : props.resize;
|
|
148
|
+
return options.value.columns === 1 ? list.filter((edge) => edge !== "e") : list;
|
|
149
|
+
});
|
|
150
|
+
const session = shallowRef(null);
|
|
151
|
+
const settling = ref(false);
|
|
152
|
+
let settleTimer;
|
|
153
|
+
const isPointer = (s) => s?.source === "pointer";
|
|
154
|
+
/**
|
|
155
|
+
* Items as drawn: the one under the pointer keeps its old place, and
|
|
156
|
+
* follows the pointer from there; one being dropped in shows only as the
|
|
157
|
+
* place it would take.
|
|
158
|
+
*/
|
|
159
|
+
const drawn = computed(() => {
|
|
160
|
+
const s = session.value;
|
|
161
|
+
if (!isPointer(s)) return layout.value;
|
|
162
|
+
if (s.kind === "drop") return layout.value.filter((item) => item.id !== s.id);
|
|
163
|
+
return layout.value.map((item) => item.id === s.id ? s.item : item);
|
|
164
|
+
});
|
|
165
|
+
/** Where the item under the pointer would land. */
|
|
166
|
+
const ghost = computed(() => {
|
|
167
|
+
const s = session.value;
|
|
168
|
+
return isPointer(s) ? layout.value.find((item) => item.id === s.id) : void 0;
|
|
169
|
+
});
|
|
170
|
+
function stateOf(id) {
|
|
171
|
+
const s = session.value;
|
|
172
|
+
if (s?.id !== id) return "idle";
|
|
173
|
+
return s.kind === "resize" ? "resizing" : "dragging";
|
|
174
|
+
}
|
|
175
|
+
const rootStyle = computed(() => ({
|
|
176
|
+
"--dou-grid-columns": options.value.columns,
|
|
177
|
+
"--dou-grid-row": `${props.rowHeight}px`,
|
|
178
|
+
"--dou-grid-gap-x": `${gaps.value[0]}px`,
|
|
179
|
+
"--dou-grid-gap-y": `${gaps.value[1]}px`,
|
|
180
|
+
"--dou-grid-rows": layoutHeight(layout.value)
|
|
181
|
+
}));
|
|
182
|
+
const cellStyle = (item) => ({
|
|
183
|
+
"--dou-grid-x": item.x,
|
|
184
|
+
"--dou-grid-y": item.y,
|
|
185
|
+
"--dou-grid-w": item.w,
|
|
186
|
+
"--dou-grid-h": item.h
|
|
187
|
+
});
|
|
188
|
+
const labelOf = (item) => props.itemLabel?.(item) ?? item.id;
|
|
189
|
+
/** Where an item is, read out: its cell and size, or with one column its place in the list. */
|
|
190
|
+
function positionText(item, items) {
|
|
191
|
+
if (options.value.columns > 1) return format(messages.value.position, {
|
|
192
|
+
x: item.x + 1,
|
|
193
|
+
y: item.y + 1,
|
|
194
|
+
w: item.w,
|
|
195
|
+
h: item.h
|
|
196
|
+
});
|
|
197
|
+
let n = 1;
|
|
198
|
+
for (const other of items) if (other.y < item.y) n++;
|
|
199
|
+
return format(messages.value.order, {
|
|
200
|
+
n,
|
|
201
|
+
count: items.length
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const live = ref("");
|
|
205
|
+
function say(text) {
|
|
206
|
+
live.value = "";
|
|
207
|
+
requestAnimationFrame(() => live.value = text);
|
|
208
|
+
}
|
|
209
|
+
const focusId = ref();
|
|
210
|
+
const firstId = computed(() => {
|
|
211
|
+
let first;
|
|
212
|
+
for (const item of settled.value) if (!first || item.y < first.y || item.y === first.y && item.x < first.x) first = item;
|
|
213
|
+
return first?.id;
|
|
214
|
+
});
|
|
215
|
+
const tabbableId = computed(() => focusId.value && settled.value.some((item) => item.id === focusId.value) ? focusId.value : firstId.value);
|
|
216
|
+
const tabindexOf = (item) => props.editable ? item.id === tabbableId.value ? 0 : -1 : void 0;
|
|
217
|
+
function itemElement(id) {
|
|
218
|
+
for (const child of root.value?.children ?? []) if (child instanceof HTMLElement && child.dataset.gridId === id) return child;
|
|
219
|
+
}
|
|
220
|
+
/** The item element an event happened on: a direct child of this grid, not of a grid inside an item. */
|
|
221
|
+
function ownItem(target) {
|
|
222
|
+
const el = target instanceof Element ? target.closest("[data-grid-id]") : null;
|
|
223
|
+
return el && el.parentElement === root.value ? el : null;
|
|
224
|
+
}
|
|
225
|
+
function onFocusIn(event) {
|
|
226
|
+
const el = ownItem(event.target);
|
|
227
|
+
if (el) focusId.value = el.dataset.gridId;
|
|
228
|
+
}
|
|
229
|
+
/** The nearest item in the direction of an arrow key. */
|
|
230
|
+
function neighbour(from, dx, dy) {
|
|
231
|
+
const cx = from.x + from.w / 2;
|
|
232
|
+
const cy = from.y + from.h / 2;
|
|
233
|
+
let best;
|
|
234
|
+
let bestScore = Infinity;
|
|
235
|
+
for (const item of settled.value) {
|
|
236
|
+
if (item === from) continue;
|
|
237
|
+
const ix = item.x + item.w / 2 - cx;
|
|
238
|
+
const iy = item.y + item.h / 2 - cy;
|
|
239
|
+
const along = dx ? ix * dx : iy * dy;
|
|
240
|
+
if (along <= 0) continue;
|
|
241
|
+
const score = along + Math.abs(dx ? iy : ix) * 2;
|
|
242
|
+
if (score < bestScore) [best, bestScore] = [item, score];
|
|
243
|
+
}
|
|
244
|
+
return best;
|
|
245
|
+
}
|
|
246
|
+
function commit(next, s, reason) {
|
|
247
|
+
if (!next || next.length === s.base.length && next.every((item, i) => item === s.base[i])) return false;
|
|
248
|
+
const breakpoint = tier.value.name;
|
|
249
|
+
const drop = s.drop;
|
|
250
|
+
let added;
|
|
251
|
+
if (isMain.value) {
|
|
252
|
+
const items = next.slice();
|
|
253
|
+
added = drop && items.find((other) => other.id === s.id);
|
|
254
|
+
model.value = items;
|
|
255
|
+
emit("change", {
|
|
256
|
+
items,
|
|
257
|
+
id: s.id,
|
|
258
|
+
reason,
|
|
259
|
+
breakpoint
|
|
260
|
+
});
|
|
261
|
+
} else {
|
|
262
|
+
if (drop) {
|
|
263
|
+
const main = mainLayout.value;
|
|
264
|
+
const wide = optionsOf(tiers.value[0]);
|
|
265
|
+
const fitted = fitItem({
|
|
266
|
+
...drop.item,
|
|
267
|
+
x: 0,
|
|
268
|
+
y: 0
|
|
269
|
+
}, wide.columns);
|
|
270
|
+
added = {
|
|
271
|
+
...fitted,
|
|
272
|
+
...findPlace(main, fitted, wide)
|
|
273
|
+
};
|
|
274
|
+
model.value = [...main, added];
|
|
275
|
+
}
|
|
276
|
+
layouts.value = {
|
|
277
|
+
...layouts.value,
|
|
278
|
+
[breakpoint]: next.map(({ id, x, y, w, h }) => ({
|
|
279
|
+
id,
|
|
280
|
+
x,
|
|
281
|
+
y,
|
|
282
|
+
w,
|
|
283
|
+
h
|
|
284
|
+
}))
|
|
285
|
+
};
|
|
286
|
+
emit("change", {
|
|
287
|
+
items: next.slice(),
|
|
288
|
+
id: s.id,
|
|
289
|
+
reason,
|
|
290
|
+
breakpoint
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (drop && added) emit("drop", {
|
|
294
|
+
item: added,
|
|
295
|
+
data: drop.data,
|
|
296
|
+
breakpoint
|
|
297
|
+
});
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
function settle() {
|
|
301
|
+
settling.value = true;
|
|
302
|
+
clearTimeout(settleTimer);
|
|
303
|
+
settleTimer = setTimeout(() => settling.value = false, SETTLE);
|
|
304
|
+
}
|
|
305
|
+
function finish(keep) {
|
|
306
|
+
const s = session.value;
|
|
307
|
+
if (!s) return;
|
|
308
|
+
const next = preview.value;
|
|
309
|
+
if (isPointer(s)) stopPointer(s);
|
|
310
|
+
session.value = null;
|
|
311
|
+
preview.value = null;
|
|
312
|
+
settle();
|
|
313
|
+
const reason = s.source === "keyboard" ? "keyboard" : s.kind;
|
|
314
|
+
const changed = keep && commit(next, s, reason);
|
|
315
|
+
emit("dragEnd", {
|
|
316
|
+
id: s.id,
|
|
317
|
+
kind: s.kind,
|
|
318
|
+
cancelled: !keep || s.kind === "drop" && !changed
|
|
319
|
+
});
|
|
320
|
+
if (s.source !== "keyboard" && (keep || s.kind === "drop") && !changed) return;
|
|
321
|
+
const items = (changed ? next : s.base) ?? s.base;
|
|
322
|
+
const item = items.find((other) => other.id === s.id) ?? s.item;
|
|
323
|
+
const label = labelOf(item);
|
|
324
|
+
say(changed || keep && s.source === "keyboard" ? format(messages.value.dropped, {
|
|
325
|
+
item: label,
|
|
326
|
+
position: positionText(item, items)
|
|
327
|
+
}) : format(messages.value.cancelled, { item: label }));
|
|
328
|
+
}
|
|
329
|
+
let press = null;
|
|
330
|
+
let pointer = {
|
|
331
|
+
x: 0,
|
|
332
|
+
y: 0
|
|
333
|
+
};
|
|
334
|
+
let frame = 0;
|
|
335
|
+
function onPointerDown(event) {
|
|
336
|
+
if (!props.editable || session.value || press || !event.isPrimary) return;
|
|
337
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
338
|
+
const target = event.target;
|
|
339
|
+
const el = ownItem(target);
|
|
340
|
+
const id = el?.dataset.gridId;
|
|
341
|
+
const item = id === void 0 ? void 0 : settled.value.find((other) => other.id === id);
|
|
342
|
+
if (!el || !id || !item || item.locked) return;
|
|
343
|
+
const handle = target.closest("[data-grid-resize]");
|
|
344
|
+
let kind = "move";
|
|
345
|
+
let edge = null;
|
|
346
|
+
if (handle && handle.parentElement === el) {
|
|
347
|
+
kind = "resize";
|
|
348
|
+
edge = handle.dataset.gridResize;
|
|
349
|
+
} else {
|
|
350
|
+
if (props.handle) {
|
|
351
|
+
const part = target.closest("[data-dou-grid-handle]");
|
|
352
|
+
if (!part || part.closest("[data-grid-id]") !== el) return;
|
|
353
|
+
}
|
|
354
|
+
if (target.closest(NO_DRAG)) return;
|
|
355
|
+
}
|
|
356
|
+
listen({
|
|
357
|
+
event,
|
|
358
|
+
el,
|
|
359
|
+
id,
|
|
360
|
+
kind,
|
|
361
|
+
edge,
|
|
362
|
+
hold: holdPointer(event, root.value)
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
/** Follows a press until it becomes a drag (or a scroll, or nothing). */
|
|
366
|
+
function listen(next) {
|
|
367
|
+
const { event } = next;
|
|
368
|
+
press = next;
|
|
369
|
+
pointer = {
|
|
370
|
+
x: event.clientX,
|
|
371
|
+
y: event.clientY
|
|
372
|
+
};
|
|
373
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
374
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
375
|
+
window.addEventListener("pointercancel", onPointerCancel);
|
|
376
|
+
if (next.kind === "resize") {
|
|
377
|
+
event.preventDefault();
|
|
378
|
+
begin();
|
|
379
|
+
} else if (event.pointerType !== "mouse") next.timer = setTimeout(begin, HOLD_DELAY);
|
|
380
|
+
}
|
|
381
|
+
function startDrop(event, item, data) {
|
|
382
|
+
if (!props.editable || session.value || press || !event.isPrimary || !root.value) return;
|
|
383
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
384
|
+
if (settled.value.some((other) => other.id === item.id)) return;
|
|
385
|
+
listen({
|
|
386
|
+
event,
|
|
387
|
+
el: root.value,
|
|
388
|
+
id: item.id,
|
|
389
|
+
kind: "drop",
|
|
390
|
+
edge: null,
|
|
391
|
+
hold: holdPointer(event, root.value),
|
|
392
|
+
drop: {
|
|
393
|
+
item,
|
|
394
|
+
data
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
function onPointerMove(event) {
|
|
399
|
+
if (!press || event.pointerId !== press.event.pointerId) return;
|
|
400
|
+
pointer = {
|
|
401
|
+
x: event.clientX,
|
|
402
|
+
y: event.clientY
|
|
403
|
+
};
|
|
404
|
+
if (!session.value) {
|
|
405
|
+
const distance = Math.hypot(pointer.x - press.event.clientX, pointer.y - press.event.clientY);
|
|
406
|
+
if (press.event.pointerType === "mouse") {
|
|
407
|
+
if (distance >= DRAG_DISTANCE) begin();
|
|
408
|
+
} else if (distance > HOLD_SLOP) dropPress();
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
track();
|
|
412
|
+
}
|
|
413
|
+
function onPointerUp(event) {
|
|
414
|
+
if (!press || event.pointerId !== press.event.pointerId) return;
|
|
415
|
+
if (session.value) finish(true);
|
|
416
|
+
else dropPress();
|
|
417
|
+
}
|
|
418
|
+
function onPointerCancel(event) {
|
|
419
|
+
if (!press || event.pointerId !== press.event.pointerId) return;
|
|
420
|
+
if (session.value) finish(false);
|
|
421
|
+
else dropPress();
|
|
422
|
+
}
|
|
423
|
+
function onWindowKeydown(event) {
|
|
424
|
+
if (event.key !== "Escape" || !isPointer(session.value)) return;
|
|
425
|
+
event.preventDefault();
|
|
426
|
+
event.stopPropagation();
|
|
427
|
+
finish(false);
|
|
428
|
+
}
|
|
429
|
+
function onScroll() {
|
|
430
|
+
if (isPointer(session.value)) track();
|
|
431
|
+
}
|
|
432
|
+
function dropPress() {
|
|
433
|
+
if (!press) return;
|
|
434
|
+
clearTimeout(press.timer);
|
|
435
|
+
press.hold.release();
|
|
436
|
+
press = null;
|
|
437
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
438
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
439
|
+
window.removeEventListener("pointercancel", onPointerCancel);
|
|
440
|
+
}
|
|
441
|
+
function scrollParent(el) {
|
|
442
|
+
for (let node = el.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
443
|
+
const { overflowY } = getComputedStyle(node);
|
|
444
|
+
if (/(auto|scroll|overlay)/.test(overflowY) && node.scrollHeight > node.clientHeight) return node;
|
|
445
|
+
}
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
const scrollOf = (scroller) => scroller ? {
|
|
449
|
+
left: scroller.scrollLeft,
|
|
450
|
+
top: scroller.scrollTop
|
|
451
|
+
} : {
|
|
452
|
+
left: window.scrollX,
|
|
453
|
+
top: window.scrollY
|
|
454
|
+
};
|
|
455
|
+
function begin() {
|
|
456
|
+
const p = press;
|
|
457
|
+
const el = root.value;
|
|
458
|
+
if (!p || !el || session.value) return;
|
|
459
|
+
clearTimeout(p.timer);
|
|
460
|
+
const item = p.drop ? fitItem({
|
|
461
|
+
...p.drop.item,
|
|
462
|
+
x: 0,
|
|
463
|
+
y: 0
|
|
464
|
+
}, options.value.columns) : settled.value.find((other) => other.id === p.id);
|
|
465
|
+
if (!item) return dropPress();
|
|
466
|
+
const rect = el.getBoundingClientRect();
|
|
467
|
+
const [gx, gy] = gaps.value;
|
|
468
|
+
const columns = options.value.columns;
|
|
469
|
+
const col = (rect.width - gx * (columns - 1)) / columns;
|
|
470
|
+
const scroller = scrollParent(el);
|
|
471
|
+
const scroll = scrollOf(scroller);
|
|
472
|
+
const box = scroller?.getBoundingClientRect();
|
|
473
|
+
session.value = {
|
|
474
|
+
id: p.id,
|
|
475
|
+
kind: p.kind,
|
|
476
|
+
source: "pointer",
|
|
477
|
+
edge: p.edge,
|
|
478
|
+
base: settled.value,
|
|
479
|
+
item,
|
|
480
|
+
el: p.el,
|
|
481
|
+
startX: p.drop ? rect.left : p.event.clientX,
|
|
482
|
+
startY: p.drop ? rect.top : p.event.clientY,
|
|
483
|
+
scroller,
|
|
484
|
+
scrollLeft: scroll.left,
|
|
485
|
+
scrollTop: scroll.top,
|
|
486
|
+
view: box ? {
|
|
487
|
+
top: box.top,
|
|
488
|
+
bottom: box.bottom
|
|
489
|
+
} : {
|
|
490
|
+
top: 0,
|
|
491
|
+
bottom: window.innerHeight
|
|
492
|
+
},
|
|
493
|
+
col,
|
|
494
|
+
colStep: col + gx,
|
|
495
|
+
rowStep: props.rowHeight + gy,
|
|
496
|
+
left: item.x * (col + gx),
|
|
497
|
+
top: item.y * (props.rowHeight + gy),
|
|
498
|
+
width: item.w * col + (item.w - 1) * gx,
|
|
499
|
+
height: item.h * props.rowHeight + (item.h - 1) * gy,
|
|
500
|
+
cell: "",
|
|
501
|
+
drop: p.drop
|
|
502
|
+
};
|
|
503
|
+
preview.value = settled.value;
|
|
504
|
+
p.hold.grab();
|
|
505
|
+
if (p.event.pointerType === "mouse") try {
|
|
506
|
+
el.setPointerCapture(p.event.pointerId);
|
|
507
|
+
} catch {}
|
|
508
|
+
window.addEventListener("keydown", onWindowKeydown, true);
|
|
509
|
+
window.addEventListener("scroll", onScroll, {
|
|
510
|
+
capture: true,
|
|
511
|
+
passive: true
|
|
512
|
+
});
|
|
513
|
+
emit("dragStart", {
|
|
514
|
+
id: p.id,
|
|
515
|
+
kind: p.kind
|
|
516
|
+
});
|
|
517
|
+
frame = requestAnimationFrame(autoscroll);
|
|
518
|
+
track();
|
|
519
|
+
}
|
|
520
|
+
function stopPointer(s) {
|
|
521
|
+
cancelAnimationFrame(frame);
|
|
522
|
+
for (const name of [
|
|
523
|
+
"dx",
|
|
524
|
+
"dy",
|
|
525
|
+
"dw",
|
|
526
|
+
"dh"
|
|
527
|
+
]) s.el.style.removeProperty(`--dou-grid-${name}`);
|
|
528
|
+
window.removeEventListener("keydown", onWindowKeydown, true);
|
|
529
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
530
|
+
const touch = press?.event.pointerType !== "mouse";
|
|
531
|
+
dropPress();
|
|
532
|
+
window.addEventListener("click", swallow, {
|
|
533
|
+
capture: true,
|
|
534
|
+
once: true
|
|
535
|
+
});
|
|
536
|
+
setTimeout(() => window.removeEventListener("click", swallow, true), touch ? 400 : 0);
|
|
537
|
+
}
|
|
538
|
+
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
539
|
+
/** The length of `n` cells of `size` with `gap` between them. */
|
|
540
|
+
const span = (n, size, gap) => n * size + (n - 1) * gap;
|
|
541
|
+
function swallow(event) {
|
|
542
|
+
event.stopPropagation();
|
|
543
|
+
event.preventDefault();
|
|
544
|
+
}
|
|
545
|
+
/** Follows the pointer: moves the item with it, and works out the layout when it reaches another cell. */
|
|
546
|
+
function track() {
|
|
547
|
+
const s = session.value;
|
|
548
|
+
if (!isPointer(s)) return;
|
|
549
|
+
const scroll = scrollOf(s.scroller);
|
|
550
|
+
const dx = pointer.x - s.startX + scroll.left - s.scrollLeft;
|
|
551
|
+
const dy = pointer.y - s.startY + scroll.top - s.scrollTop;
|
|
552
|
+
const { columns } = options.value;
|
|
553
|
+
const [gx, gy] = gaps.value;
|
|
554
|
+
const item = s.item;
|
|
555
|
+
if (s.kind === "drop") {
|
|
556
|
+
const height = layoutHeight(s.base) * s.rowStep;
|
|
557
|
+
const over = dx > -s.colStep / 2 && dx < s.colStep * columns && dy > -s.rowStep / 2 && dy < height + s.rowStep * (item.h + 1);
|
|
558
|
+
const x = clamp(Math.round((dx - s.width / 2) / s.colStep), 0, columns - item.w);
|
|
559
|
+
const y = Math.max(0, Math.round((dy - s.height / 2) / s.rowStep));
|
|
560
|
+
const cell = over ? `${x},${y}` : "out";
|
|
561
|
+
if (cell === s.cell) return;
|
|
562
|
+
s.cell = cell;
|
|
563
|
+
preview.value = over ? moveItem([...s.base, {
|
|
564
|
+
...item,
|
|
565
|
+
x,
|
|
566
|
+
y
|
|
567
|
+
}], s.id, {
|
|
568
|
+
x,
|
|
569
|
+
y
|
|
570
|
+
}, options.value) : s.base;
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (s.kind === "move") {
|
|
574
|
+
s.el.style.setProperty("--dou-grid-dx", `${dx}px`);
|
|
575
|
+
s.el.style.setProperty("--dou-grid-dy", `${dy}px`);
|
|
576
|
+
const x = clamp(Math.round((s.left + dx) / s.colStep), 0, columns - item.w);
|
|
577
|
+
const y = Math.max(0, Math.round((s.top + dy) / s.rowStep));
|
|
578
|
+
const cell = `${x},${y}`;
|
|
579
|
+
if (cell === s.cell) return;
|
|
580
|
+
s.cell = cell;
|
|
581
|
+
preview.value = moveItem(s.base, s.id, {
|
|
582
|
+
x,
|
|
583
|
+
y
|
|
584
|
+
}, options.value);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const maxW = Math.min(columns - item.x, item.maxW ?? Infinity);
|
|
588
|
+
const minW = Math.min(maxW, Math.max(1, item.minW ?? 1));
|
|
589
|
+
const maxH = item.maxH ?? Infinity;
|
|
590
|
+
const minH = Math.min(maxH, Math.max(1, item.minH ?? 1));
|
|
591
|
+
const width = s.edge === "s" ? s.width : clamp(s.width + dx, span(minW, s.col, gx), span(maxW, s.col, gx));
|
|
592
|
+
const height = s.edge === "e" ? s.height : clamp(s.height + dy, span(minH, props.rowHeight, gy), span(maxH, props.rowHeight, gy));
|
|
593
|
+
s.el.style.setProperty("--dou-grid-dw", `${width - s.width}px`);
|
|
594
|
+
s.el.style.setProperty("--dou-grid-dh", `${height - s.height}px`);
|
|
595
|
+
const w = Math.round((width + gx) / s.colStep);
|
|
596
|
+
const h = Math.round((height + gy) / s.rowStep);
|
|
597
|
+
const cell = `${w}x${h}`;
|
|
598
|
+
if (cell === s.cell) return;
|
|
599
|
+
s.cell = cell;
|
|
600
|
+
preview.value = resizeItem(s.base, s.id, {
|
|
601
|
+
w,
|
|
602
|
+
h
|
|
603
|
+
}, options.value);
|
|
604
|
+
}
|
|
605
|
+
function autoscroll() {
|
|
606
|
+
const s = session.value;
|
|
607
|
+
if (!isPointer(s)) return;
|
|
608
|
+
frame = requestAnimationFrame(autoscroll);
|
|
609
|
+
const { top, bottom } = s.view;
|
|
610
|
+
let speed = 0;
|
|
611
|
+
if (pointer.y < top + EDGE) speed = -Math.min(1, (top + EDGE - pointer.y) / EDGE);
|
|
612
|
+
else if (pointer.y > bottom - EDGE) speed = Math.min(1, (pointer.y - bottom + EDGE) / EDGE);
|
|
613
|
+
if (!speed) return;
|
|
614
|
+
if (s.scroller) s.scroller.scrollTop += speed * EDGE_SPEED;
|
|
615
|
+
else window.scrollBy(0, speed * EDGE_SPEED);
|
|
616
|
+
}
|
|
617
|
+
const ARROWS = {
|
|
618
|
+
ArrowLeft: [-1, 0],
|
|
619
|
+
ArrowRight: [1, 0],
|
|
620
|
+
ArrowUp: [0, -1],
|
|
621
|
+
ArrowDown: [0, 1]
|
|
622
|
+
};
|
|
623
|
+
function onKeyDown(event) {
|
|
624
|
+
if (!props.editable || event.target !== ownItem(event.target)) return;
|
|
625
|
+
const id = event.target.dataset.gridId;
|
|
626
|
+
const s = session.value;
|
|
627
|
+
const arrow = ARROWS[event.key];
|
|
628
|
+
if (s?.source === "keyboard" && s.id === id) {
|
|
629
|
+
if (arrow && !event.altKey && !event.metaKey && !event.ctrlKey) {
|
|
630
|
+
const current = preview.value ?? s.base;
|
|
631
|
+
const next = event.shiftKey ? resizeItemBy(current, id, arrow[0], arrow[1], options.value) : moveItemBy(current, id, arrow[0], arrow[1], options.value);
|
|
632
|
+
preview.value = next;
|
|
633
|
+
const item = next.find((other) => other.id === id);
|
|
634
|
+
if (item) say(positionText(item, next));
|
|
635
|
+
} else if (event.key === "Enter" || event.key === " ") finish(true);
|
|
636
|
+
else if (event.key === "Escape") finish(false);
|
|
637
|
+
else if (event.key !== "Tab") return;
|
|
638
|
+
if (event.key !== "Tab") {
|
|
639
|
+
event.preventDefault();
|
|
640
|
+
event.stopPropagation();
|
|
641
|
+
}
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
if (s) return;
|
|
645
|
+
const item = settled.value.find((other) => other.id === id);
|
|
646
|
+
if (!item) return;
|
|
647
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
648
|
+
event.preventDefault();
|
|
649
|
+
if (item.locked) return say(format(messages.value.locked, { item: labelOf(item) }));
|
|
650
|
+
session.value = {
|
|
651
|
+
id,
|
|
652
|
+
kind: "move",
|
|
653
|
+
source: "keyboard",
|
|
654
|
+
base: settled.value,
|
|
655
|
+
item
|
|
656
|
+
};
|
|
657
|
+
preview.value = settled.value;
|
|
658
|
+
emit("dragStart", {
|
|
659
|
+
id,
|
|
660
|
+
kind: "move"
|
|
661
|
+
});
|
|
662
|
+
say(format(messages.value.grabbed, {
|
|
663
|
+
item: labelOf(item),
|
|
664
|
+
position: positionText(item, settled.value)
|
|
665
|
+
}));
|
|
666
|
+
} else if (arrow && !event.shiftKey && !event.altKey && !event.metaKey && !event.ctrlKey) {
|
|
667
|
+
const next = neighbour(item, arrow[0], arrow[1]);
|
|
668
|
+
if (!next) return;
|
|
669
|
+
event.preventDefault();
|
|
670
|
+
itemElement(next.id)?.focus();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
/** Leaving a picked-up item puts it back. */
|
|
674
|
+
function onFocusOut(event) {
|
|
675
|
+
const s = session.value;
|
|
676
|
+
if (s?.source !== "keyboard") return;
|
|
677
|
+
const el = ownItem(event.target);
|
|
678
|
+
if (el?.dataset.gridId === s.id && !el.contains(event.relatedTarget)) finish(false);
|
|
679
|
+
}
|
|
680
|
+
watch(() => props.editable, (editable) => {
|
|
681
|
+
if (!editable) {
|
|
682
|
+
finish(false);
|
|
683
|
+
dropPress();
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
onBeforeUnmount(() => {
|
|
687
|
+
finish(false);
|
|
688
|
+
dropPress();
|
|
689
|
+
clearTimeout(settleTimer);
|
|
690
|
+
});
|
|
691
|
+
__expose({
|
|
692
|
+
startDrop,
|
|
693
|
+
get breakpoint() {
|
|
694
|
+
return tier.value.name;
|
|
695
|
+
},
|
|
696
|
+
focusItem(id) {
|
|
697
|
+
const el = itemElement(id);
|
|
698
|
+
if (!el) return;
|
|
699
|
+
if (props.editable) el.focus();
|
|
700
|
+
else el.querySelector("a[href], button:not([disabled]), input:not([disabled]), select, textarea, [tabindex]:not([tabindex=\"-1\"])")?.focus();
|
|
701
|
+
},
|
|
702
|
+
scrollToItem(id, scrollOptions) {
|
|
703
|
+
itemElement(id)?.scrollIntoView({
|
|
704
|
+
block: "nearest",
|
|
705
|
+
inline: "nearest",
|
|
706
|
+
...scrollOptions
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
return (_ctx, _cache) => {
|
|
711
|
+
return openBlock(), createElementBlock("div", {
|
|
712
|
+
ref_key: "root",
|
|
713
|
+
ref: root,
|
|
714
|
+
class: normalizeClass(["dou-grid-layout", {
|
|
715
|
+
"is-editable": __props.editable,
|
|
716
|
+
"has-handle": __props.handle,
|
|
717
|
+
"is-arranging": !!session.value || settling.value,
|
|
718
|
+
"is-pointer-dragging": session.value?.source === "pointer",
|
|
719
|
+
"is-resizing": session.value?.kind === "resize" && session.value.source === "pointer"
|
|
720
|
+
}]),
|
|
721
|
+
style: normalizeStyle(rootStyle.value),
|
|
722
|
+
role: __props.editable ? "group" : void 0,
|
|
723
|
+
"aria-label": __props.label ?? (__props.editable ? unref(messages).layout : void 0),
|
|
724
|
+
onPointerdown: onPointerDown,
|
|
725
|
+
onKeydown: onKeyDown,
|
|
726
|
+
onFocusin: onFocusIn,
|
|
727
|
+
onFocusout: onFocusOut
|
|
728
|
+
}, [
|
|
729
|
+
ghost.value ? (openBlock(), createElementBlock("div", {
|
|
730
|
+
key: 0,
|
|
731
|
+
class: "dou-grid-layout__placeholder",
|
|
732
|
+
style: normalizeStyle(cellStyle(ghost.value)),
|
|
733
|
+
"aria-hidden": "true"
|
|
734
|
+
}, [renderSlot(_ctx.$slots, "placeholder", { item: ghost.value })], 4)) : createCommentVNode("", true),
|
|
735
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(drawn.value, (item) => {
|
|
736
|
+
return openBlock(), createBlock(unref(grid_item_default), {
|
|
737
|
+
key: item.id,
|
|
738
|
+
item,
|
|
739
|
+
state: stateOf(item.id),
|
|
740
|
+
editable: __props.editable,
|
|
741
|
+
tabindex: tabindexOf(item),
|
|
742
|
+
label: labelOf(item),
|
|
743
|
+
"role-description": unref(messages).item,
|
|
744
|
+
handles: handles.value
|
|
745
|
+
}, null, 8, [
|
|
746
|
+
"item",
|
|
747
|
+
"state",
|
|
748
|
+
"editable",
|
|
749
|
+
"tabindex",
|
|
750
|
+
"label",
|
|
751
|
+
"role-description",
|
|
752
|
+
"handles"
|
|
753
|
+
]);
|
|
754
|
+
}), 128)),
|
|
755
|
+
__props.editable ? (openBlock(), createElementBlock("span", {
|
|
756
|
+
key: 1,
|
|
757
|
+
id: hintId,
|
|
758
|
+
hidden: ""
|
|
759
|
+
}, toDisplayString(unref(messages).itemHint), 1)) : createCommentVNode("", true),
|
|
760
|
+
__props.editable ? (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(live.value), 1)) : createCommentVNode("", true)
|
|
761
|
+
], 46, _hoisted_1);
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
export { grid_layout_vue_vue_type_script_setup_true_lang_default as default };
|
|
766
|
+
|
|
767
|
+
//# sourceMappingURL=grid-layout.vue_vue_type_script_setup_true_lang.js.map
|