@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.
Files changed (188) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/chart/chart-settings.js +6 -0
  4. package/dist/chart/chart-settings.js.map +1 -0
  5. package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js +122 -0
  6. package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  7. package/dist/chart/chart.js +6 -0
  8. package/dist/chart/chart.js.map +1 -0
  9. package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js +99 -0
  10. package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/chart/index.js +33 -0
  12. package/dist/chart/index.js.map +1 -0
  13. package/dist/collaboration/index.js +281 -0
  14. package/dist/collaboration/index.js.map +1 -0
  15. package/dist/collaboration/order.js +88 -0
  16. package/dist/collaboration/order.js.map +1 -0
  17. package/dist/core/document.js +128 -0
  18. package/dist/core/document.js.map +1 -0
  19. package/dist/core/history.js +66 -0
  20. package/dist/core/history.js.map +1 -0
  21. package/dist/core/transaction.js +218 -0
  22. package/dist/core/transaction.js.map +1 -0
  23. package/dist/dashboard/dashboard.js +6 -0
  24. package/dist/dashboard/dashboard.js.map +1 -0
  25. package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js +1072 -0
  26. package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  27. package/dist/dashboard/export.js +77 -0
  28. package/dist/dashboard/export.js.map +1 -0
  29. package/dist/dashboard/filter-bar.js +6 -0
  30. package/dist/dashboard/filter-bar.js.map +1 -0
  31. package/dist/dashboard/filter-bar.vue_vue_type_script_setup_true_lang.js +150 -0
  32. package/dist/dashboard/filter-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  33. package/dist/dashboard/frame-context.js +5 -0
  34. package/dist/dashboard/frame-context.js.map +1 -0
  35. package/dist/dashboard/observers.js +48 -0
  36. package/dist/dashboard/observers.js.map +1 -0
  37. package/dist/dashboard/palette.js +6 -0
  38. package/dist/dashboard/palette.js.map +1 -0
  39. package/dist/dashboard/palette.vue_vue_type_script_setup_true_lang.js +54 -0
  40. package/dist/dashboard/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/dashboard/widget-body.js +6 -0
  42. package/dist/dashboard/widget-body.js.map +1 -0
  43. package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js +96 -0
  44. package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/dashboard/widget-frame.js +6 -0
  46. package/dist/dashboard/widget-frame.js.map +1 -0
  47. package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +300 -0
  48. package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -0
  49. package/dist/dashboard/widget-settings.js +6 -0
  50. package/dist/dashboard/widget-settings.js.map +1 -0
  51. package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js +36 -0
  52. package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  53. package/dist/data/context.js +5 -0
  54. package/dist/data/context.js.map +1 -0
  55. package/dist/data/filters.js +31 -0
  56. package/dist/data/filters.js.map +1 -0
  57. package/dist/data/store.js +214 -0
  58. package/dist/data/store.js.map +1 -0
  59. package/dist/grid/grid-handle.js +6 -0
  60. package/dist/grid/grid-handle.js.map +1 -0
  61. package/dist/grid/grid-handle.vue_vue_type_script_setup_true_lang.js +21 -0
  62. package/dist/grid/grid-handle.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/grid/grid-item.js +80 -0
  64. package/dist/grid/grid-item.js.map +1 -0
  65. package/dist/grid/grid-layout.js +6 -0
  66. package/dist/grid/grid-layout.js.map +1 -0
  67. package/dist/grid/grid-layout.vue_vue_type_script_setup_true_lang.js +767 -0
  68. package/dist/grid/grid-layout.vue_vue_type_script_setup_true_lang.js.map +1 -0
  69. package/dist/grid/tiers.js +31 -0
  70. package/dist/grid/tiers.js.map +1 -0
  71. package/dist/index.js +23 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/layout/engine.js +284 -0
  74. package/dist/layout/engine.js.map +1 -0
  75. package/dist/layout/index.js +1 -0
  76. package/dist/locale.js +245 -0
  77. package/dist/locale.js.map +1 -0
  78. package/dist/pivot/index.js +47 -0
  79. package/dist/pivot/index.js.map +1 -0
  80. package/dist/pivot/pivot-settings.js +6 -0
  81. package/dist/pivot/pivot-settings.js.map +1 -0
  82. package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js +64 -0
  83. package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  84. package/dist/pivot/pivot.js +6 -0
  85. package/dist/pivot/pivot.js.map +1 -0
  86. package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js +76 -0
  87. package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -0
  88. package/dist/style.css +1 -0
  89. package/dist/style.d.ts +1 -0
  90. package/dist/style.js +12 -0
  91. package/dist/types/chart/chart-settings.vue.d.ts +11 -0
  92. package/dist/types/chart/chart.vue.d.ts +3 -0
  93. package/dist/types/chart/index.d.ts +9 -0
  94. package/dist/types/chart/types.d.ts +23 -0
  95. package/dist/types/collaboration/index.d.ts +53 -0
  96. package/dist/types/collaboration/order.d.ts +20 -0
  97. package/dist/types/core/collaboration.d.ts +51 -0
  98. package/dist/types/core/document.d.ts +35 -0
  99. package/dist/types/core/history.d.ts +15 -0
  100. package/dist/types/core/transaction.d.ts +86 -0
  101. package/dist/types/core/types.d.ts +27 -0
  102. package/dist/types/dashboard/dashboard.vue.d.ts +33 -0
  103. package/dist/types/dashboard/export.d.ts +11 -0
  104. package/dist/types/dashboard/filter-bar.vue.d.ts +19 -0
  105. package/dist/types/dashboard/frame-context.d.ts +54 -0
  106. package/dist/types/dashboard/observers.d.ts +15 -0
  107. package/dist/types/dashboard/palette.vue.d.ts +20 -0
  108. package/dist/types/dashboard/types.d.ts +190 -0
  109. package/dist/types/dashboard/widget-body.vue.d.ts +19 -0
  110. package/dist/types/dashboard/widget-frame.vue.d.ts +6 -0
  111. package/dist/types/dashboard/widget-settings.vue.d.ts +16 -0
  112. package/dist/types/data/context.d.ts +18 -0
  113. package/dist/types/data/filters.d.ts +9 -0
  114. package/dist/types/data/store.d.ts +48 -0
  115. package/dist/types/data/types.d.ts +67 -0
  116. package/dist/types/grid/grid-handle.vue.d.ts +18 -0
  117. package/dist/types/grid/grid-item.d.ts +78 -0
  118. package/dist/types/grid/grid-layout.vue.d.ts +46 -0
  119. package/dist/types/grid/tiers.d.ts +12 -0
  120. package/dist/types/grid/types.d.ts +113 -0
  121. package/dist/types/index.d.ts +295 -0
  122. package/dist/types/layout/engine.d.ts +50 -0
  123. package/dist/types/layout/index.d.ts +2 -0
  124. package/dist/types/layout/types.d.ts +39 -0
  125. package/dist/types/locale.d.ts +117 -0
  126. package/dist/types/pivot/index.d.ts +14 -0
  127. package/dist/types/pivot/pivot-settings.vue.d.ts +16 -0
  128. package/dist/types/pivot/pivot.vue.d.ts +7 -0
  129. package/dist/types/pivot/types.d.ts +11 -0
  130. package/dist/types/widget/context.d.ts +91 -0
  131. package/dist/types/widget/define.d.ts +50 -0
  132. package/dist/types/widgets/field-select.vue.d.ts +18 -0
  133. package/dist/types/widgets/index.d.ts +15 -0
  134. package/dist/types/widgets/settings-field.vue.d.ts +17 -0
  135. package/dist/types/widgets/shared.d.ts +20 -0
  136. package/dist/types/widgets/source-field.vue.d.ts +15 -0
  137. package/dist/types/widgets/stat-settings.vue.d.ts +11 -0
  138. package/dist/types/widgets/stat.vue.d.ts +3 -0
  139. package/dist/types/widgets/table-settings.vue.d.ts +11 -0
  140. package/dist/types/widgets/table.vue.d.ts +3 -0
  141. package/dist/types/widgets/text-settings.vue.d.ts +11 -0
  142. package/dist/types/widgets/text.vue.d.ts +3 -0
  143. package/dist/types/widgets/types.d.ts +38 -0
  144. package/dist/widget/context.js +88 -0
  145. package/dist/widget/context.js.map +1 -0
  146. package/dist/widget/define.js +32 -0
  147. package/dist/widget/define.js.map +1 -0
  148. package/dist/widgets/field-select.js +6 -0
  149. package/dist/widgets/field-select.js.map +1 -0
  150. package/dist/widgets/field-select.vue_vue_type_script_setup_true_lang.js +54 -0
  151. package/dist/widgets/field-select.vue_vue_type_script_setup_true_lang.js.map +1 -0
  152. package/dist/widgets/index.js +74 -0
  153. package/dist/widgets/index.js.map +1 -0
  154. package/dist/widgets/settings-field.js +6 -0
  155. package/dist/widgets/settings-field.js.map +1 -0
  156. package/dist/widgets/settings-field.vue_vue_type_script_setup_true_lang.js +28 -0
  157. package/dist/widgets/settings-field.vue_vue_type_script_setup_true_lang.js.map +1 -0
  158. package/dist/widgets/shared.js +68 -0
  159. package/dist/widgets/shared.js.map +1 -0
  160. package/dist/widgets/source-field.js +6 -0
  161. package/dist/widgets/source-field.js.map +1 -0
  162. package/dist/widgets/source-field.vue_vue_type_script_setup_true_lang.js +47 -0
  163. package/dist/widgets/source-field.vue_vue_type_script_setup_true_lang.js.map +1 -0
  164. package/dist/widgets/stat-settings.js +6 -0
  165. package/dist/widgets/stat-settings.js.map +1 -0
  166. package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js +107 -0
  167. package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  168. package/dist/widgets/stat.js +6 -0
  169. package/dist/widgets/stat.js.map +1 -0
  170. package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js +72 -0
  171. package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js.map +1 -0
  172. package/dist/widgets/table-settings.js +6 -0
  173. package/dist/widgets/table-settings.js.map +1 -0
  174. package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js +90 -0
  175. package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  176. package/dist/widgets/table.js +6 -0
  177. package/dist/widgets/table.js.map +1 -0
  178. package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js +91 -0
  179. package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js.map +1 -0
  180. package/dist/widgets/text-settings.js +6 -0
  181. package/dist/widgets/text-settings.js.map +1 -0
  182. package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js +63 -0
  183. package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js.map +1 -0
  184. package/dist/widgets/text.js +6 -0
  185. package/dist/widgets/text.js.map +1 -0
  186. package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js +16 -0
  187. package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js.map +1 -0
  188. 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