@dou-ui/dashboard 0.1.0-alpha.1 → 0.1.0-alpha.3
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/dashboard/widget-frame.js.map +1 -1
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +6 -8
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layout/engine.js +176 -16
- package/dist/layout/engine.js.map +1 -1
- package/dist/pivot/pivot.js.map +1 -1
- package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/style.js +7 -1
- package/dist/types/layout/engine.d.ts +4 -3
- package/dist/widgets/table.js.map +1 -1
- package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js +1 -0
- package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-frame.js","names":["_sfc_main"],"sources":["../../src/dashboard/widget-frame.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DownloadIcon, MaximizeIcon, MoreHorizontalIcon } from '@dou-ui/icons'\nimport {\n DouAlert,\n DouButton,\n DouDropdown,\n DouDropdownItem,\n DouDropdownSub,\n DouEditable,\n DouTag,\n DouTooltip,\n} from 'dou-ui'\nimport type { DropdownValue } from 'dou-ui'\nimport { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport GridLayoutHandle from '../grid/grid-handle.vue'\nimport { format } from '../locale'\nimport { frameContextKey } from './frame-context'\nimport type { WidgetAction } from './frame-context'\nimport { observersKey } from './observers'\nimport WidgetBody from './widget-body.vue'\n\ndefineOptions({ name: 'DouDashboardWidget' })\n\nconst props = defineProps<{ id: string }>()\n\nconst frame = inject(frameContextKey)!\nconst widget = computed(() => frame.widget(props.id))\nconst type = computed(() => widget.value && frame.type(widget.value))\nconst title = computed(() => (widget.value ? frame.title(widget.value) : ''))\nconst editing = computed(() => frame.editing())\nconst messages = computed(() => frame.messages())\n/** The filters this widget set, each with a button to clear it. */\nconst linked = computed(() => frame.linked(props.id))\n/** All of them in one tag (a pivot table's click sets one per field), cleared together. */\nconst linkLabel = computed(() => linked.value.map((link) => link.label).join(' / '))\nfunction clearLinks() {\n for (const link of linked.value) frame.clearFilter(link.key)\n}\n\n/** Others at this widget, when editing together: an outline in the first one's color and their names. */\nconst peers = computed(() => frame.peers(props.id))\nconst peerText = (peer: { name: string; action: string }) => {\n const m = messages.value\n const text =\n peer.action === 'move'\n ? m.peerMoving\n : peer.action === 'resize'\n ? m.peerResizing\n : peer.action === 'settings'\n ? m.peerSettings\n : '{name}'\n return format(text, { name: peer.name })\n}\n\nconst renaming = ref(false)\n\n// Widgets far out of view show only their title until they come near: with\n// hundreds of widgets, their contents and controls are most of the mounting.\nconst root = ref<HTMLElement>()\nconst active = ref(frame.eager(props.id))\nconst observers = inject(observersKey)\nlet stop: (() => void) | undefined\nonMounted(() => {\n if (active.value || !observers) {\n active.value = true\n return\n }\n stop = observers.near(root.value!, () => {\n active.value = true\n stop?.()\n })\n})\nonBeforeUnmount(() => stop?.())\n// the dashboard draws everything for an export only when this widget isn't drawn yet\nwatch(active, (drawn) => frame.setDrawn(props.id, drawn), { immediate: true })\nonBeforeUnmount(() => frame.setDrawn(props.id, false))\n// drawn in full to export or print the dashboard, and kept that way\nwatch(\n () => frame.all(),\n (all) => {\n if (!all || active.value) return\n active.value = true\n stop?.()\n },\n { immediate: true },\n)\nconst canFullscreen = computed(() => type.value?.fullscreen !== false)\n\nconst emitAction = (action: WidgetAction) => frame.action(props.id, action)\n\n/** The file types this widget's content can be exported as; none unless it gives a workbook. */\nconst exporters = computed(() => frame.exporters(props.id))\nconst exportError = computed(() => frame.exportError(props.id))\nconst exporting = computed(() => frame.exporting(props.id))\nconst EXPORT = 'export:'\nconst exportOpen = ref(false)\n\nfunction onSelect(value: DropdownValue | undefined) {\n if (typeof value !== 'string') return\n if (value.startsWith(EXPORT)) frame.exportTo(props.id, value.slice(EXPORT.length))\n else emitAction(value as WidgetAction)\n}\n</script>\n\n<template>\n <!-- outside the frame, which cuts off what overflows it -->\n <div v-if=\"widget && peers.length\" class=\"dou-dashboard__peers\" aria-hidden=\"true\">\n <span\n v-for=\"peer in peers\"\n :key=\"`${peer.client}:${peer.action}`\"\n :class=\"['dou-dashboard__peer', `is-${peer.action}`]\"\n :style=\"{ '--dou-dashboard-peer-color': peer.color }\"\n >\n {{ peerText(peer) }}\n </span>\n </div>\n <div\n v-if=\"widget\"\n ref=\"root\"\n :class=\"['dou-dashboard__widget', peers.length && 'has-peers']\"\n :style=\"peers.length ? { '--dou-dashboard-peer-color': peers[0]!.color } : undefined\"\n >\n <template v-if=\"!active\">\n <div class=\"dou-dashboard__header\">\n <div class=\"dou-dashboard__title\">{{ title }}</div>\n </div>\n <div class=\"dou-dashboard__body\" />\n </template>\n <component\n v-else\n :is=\"editing ? GridLayoutHandle : 'div'\"\n :as=\"editing ? 'header' : undefined\"\n class=\"dou-dashboard__header\"\n >\n <DouEditable\n v-if=\"editing\"\n v-model:editing=\"renaming\"\n class=\"dou-dashboard__title\"\n :model-value=\"title\"\n trigger=\"dblclick\"\n select-on-edit\n :aria-label=\"messages.titleField\"\n :data-dou-nodrag=\"renaming ? '' : undefined\"\n @submit=\"(value) => frame.rename(id, value)\"\n />\n <div v-else class=\"dou-dashboard__title\">{{ title }}</div>\n <div v-if=\"linked.length\" class=\"dou-dashboard__links\" data-dou-nodrag>\n <DouTag\n size=\"sm\"\n closable\n :close-label=\"format(messages.clearFilter, { value: linkLabel })\"\n @close=\"clearLinks\"\n >\n {{ format(messages.filteredBy, { value: linkLabel }) }}\n </DouTag>\n </div>\n <div class=\"dou-dashboard__actions\" data-dou-nodrag>\n <DouDropdown v-if=\"editing\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton size=\"sm\" variant=\"ghost\" :aria-label=\"messages.widgetMenu\">\n <MoreHorizontalIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem value=\"settings\">{{ messages.settings }}</DouDropdownItem>\n <DouDropdownItem v-if=\"canFullscreen\" value=\"fullscreen\">\n {{ messages.fullscreen }}\n </DouDropdownItem>\n <DouDropdownSub v-if=\"exporters.length\" :title=\"messages.export\">\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n :disabled=\"exporting\"\n >\n <template v-if=\"exporter.icon\" #prefix><component :is=\"exporter.icon\" /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem value=\"duplicate\" shortcut=\"mod+d\">\n {{ messages.duplicate }}\n </DouDropdownItem>\n <DouDropdownItem value=\"remove\" tone=\"danger\" shortcut=\"delete\" divided>\n {{ messages.remove }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n <DouTooltip
|
|
1
|
+
{"version":3,"file":"widget-frame.js","names":["_sfc_main"],"sources":["../../src/dashboard/widget-frame.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DownloadIcon, MaximizeIcon, MoreHorizontalIcon } from '@dou-ui/icons'\nimport {\n DouAlert,\n DouButton,\n DouDropdown,\n DouDropdownItem,\n DouDropdownSub,\n DouEditable,\n DouTag,\n DouTooltip,\n} from 'dou-ui'\nimport type { DropdownValue } from 'dou-ui'\nimport { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport GridLayoutHandle from '../grid/grid-handle.vue'\nimport { format } from '../locale'\nimport { frameContextKey } from './frame-context'\nimport type { WidgetAction } from './frame-context'\nimport { observersKey } from './observers'\nimport WidgetBody from './widget-body.vue'\n\ndefineOptions({ name: 'DouDashboardWidget' })\n\nconst props = defineProps<{ id: string }>()\n\nconst frame = inject(frameContextKey)!\nconst widget = computed(() => frame.widget(props.id))\nconst type = computed(() => widget.value && frame.type(widget.value))\nconst title = computed(() => (widget.value ? frame.title(widget.value) : ''))\nconst editing = computed(() => frame.editing())\nconst messages = computed(() => frame.messages())\n/** The filters this widget set, each with a button to clear it. */\nconst linked = computed(() => frame.linked(props.id))\n/** All of them in one tag (a pivot table's click sets one per field), cleared together. */\nconst linkLabel = computed(() => linked.value.map((link) => link.label).join(' / '))\nfunction clearLinks() {\n for (const link of linked.value) frame.clearFilter(link.key)\n}\n\n/** Others at this widget, when editing together: an outline in the first one's color and their names. */\nconst peers = computed(() => frame.peers(props.id))\nconst peerText = (peer: { name: string; action: string }) => {\n const m = messages.value\n const text =\n peer.action === 'move'\n ? m.peerMoving\n : peer.action === 'resize'\n ? m.peerResizing\n : peer.action === 'settings'\n ? m.peerSettings\n : '{name}'\n return format(text, { name: peer.name })\n}\n\nconst renaming = ref(false)\n\n// Widgets far out of view show only their title until they come near: with\n// hundreds of widgets, their contents and controls are most of the mounting.\nconst root = ref<HTMLElement>()\nconst active = ref(frame.eager(props.id))\nconst observers = inject(observersKey)\nlet stop: (() => void) | undefined\nonMounted(() => {\n if (active.value || !observers) {\n active.value = true\n return\n }\n stop = observers.near(root.value!, () => {\n active.value = true\n stop?.()\n })\n})\nonBeforeUnmount(() => stop?.())\n// the dashboard draws everything for an export only when this widget isn't drawn yet\nwatch(active, (drawn) => frame.setDrawn(props.id, drawn), { immediate: true })\nonBeforeUnmount(() => frame.setDrawn(props.id, false))\n// drawn in full to export or print the dashboard, and kept that way\nwatch(\n () => frame.all(),\n (all) => {\n if (!all || active.value) return\n active.value = true\n stop?.()\n },\n { immediate: true },\n)\nconst canFullscreen = computed(() => type.value?.fullscreen !== false)\n\nconst emitAction = (action: WidgetAction) => frame.action(props.id, action)\n\n/** The file types this widget's content can be exported as; none unless it gives a workbook. */\nconst exporters = computed(() => frame.exporters(props.id))\nconst exportError = computed(() => frame.exportError(props.id))\nconst exporting = computed(() => frame.exporting(props.id))\nconst EXPORT = 'export:'\nconst exportOpen = ref(false)\n\nfunction onSelect(value: DropdownValue | undefined) {\n if (typeof value !== 'string') return\n if (value.startsWith(EXPORT)) frame.exportTo(props.id, value.slice(EXPORT.length))\n else emitAction(value as WidgetAction)\n}\n</script>\n\n<template>\n <!-- outside the frame, which cuts off what overflows it -->\n <div v-if=\"widget && peers.length\" class=\"dou-dashboard__peers\" aria-hidden=\"true\">\n <span\n v-for=\"peer in peers\"\n :key=\"`${peer.client}:${peer.action}`\"\n :class=\"['dou-dashboard__peer', `is-${peer.action}`]\"\n :style=\"{ '--dou-dashboard-peer-color': peer.color }\"\n >\n {{ peerText(peer) }}\n </span>\n </div>\n <div\n v-if=\"widget\"\n ref=\"root\"\n :class=\"['dou-dashboard__widget', peers.length && 'has-peers']\"\n :style=\"peers.length ? { '--dou-dashboard-peer-color': peers[0]!.color } : undefined\"\n >\n <template v-if=\"!active\">\n <div class=\"dou-dashboard__header\">\n <div class=\"dou-dashboard__title\">{{ title }}</div>\n </div>\n <div class=\"dou-dashboard__body\" />\n </template>\n <component\n v-else\n :is=\"editing ? GridLayoutHandle : 'div'\"\n :as=\"editing ? 'header' : undefined\"\n class=\"dou-dashboard__header\"\n >\n <DouEditable\n v-if=\"editing\"\n v-model:editing=\"renaming\"\n class=\"dou-dashboard__title\"\n :model-value=\"title\"\n trigger=\"dblclick\"\n select-on-edit\n :aria-label=\"messages.titleField\"\n :data-dou-nodrag=\"renaming ? '' : undefined\"\n @submit=\"(value) => frame.rename(id, value)\"\n />\n <div v-else class=\"dou-dashboard__title\">{{ title }}</div>\n <div v-if=\"linked.length\" class=\"dou-dashboard__links\" data-dou-nodrag>\n <DouTag\n size=\"sm\"\n closable\n :close-label=\"format(messages.clearFilter, { value: linkLabel })\"\n @close=\"clearLinks\"\n >\n {{ format(messages.filteredBy, { value: linkLabel }) }}\n </DouTag>\n </div>\n <div class=\"dou-dashboard__actions\" data-dou-nodrag>\n <DouDropdown v-if=\"editing\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton size=\"sm\" variant=\"ghost\" :aria-label=\"messages.widgetMenu\">\n <MoreHorizontalIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem value=\"settings\">{{ messages.settings }}</DouDropdownItem>\n <DouDropdownItem v-if=\"canFullscreen\" value=\"fullscreen\">\n {{ messages.fullscreen }}\n </DouDropdownItem>\n <DouDropdownSub v-if=\"exporters.length\" :title=\"messages.export\">\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n :disabled=\"exporting\"\n >\n <template v-if=\"exporter.icon\" #prefix><component :is=\"exporter.icon\" /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem value=\"duplicate\" shortcut=\"mod+d\">\n {{ messages.duplicate }}\n </DouDropdownItem>\n <DouDropdownItem value=\"remove\" tone=\"danger\" shortcut=\"delete\" divided>\n {{ messages.remove }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n <DouTooltip v-if=\"!editing && exporters.length\" :content=\"messages.export\">\n <DouDropdown v-model:open=\"exportOpen\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.export\"\n :loading=\"exporting\"\n :disabled=\"exporting\"\n >\n <DownloadIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n >\n <template v-if=\"exporter.icon\" #prefix><component :is=\"exporter.icon\" /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n </DouTooltip>\n <DouTooltip v-if=\"!editing && canFullscreen\" :content=\"messages.fullscreen\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.fullscreen\"\n @click=\"emitAction('fullscreen')\"\n >\n <MaximizeIcon />\n </DouButton>\n </DouTooltip>\n </div>\n </component>\n <div v-if=\"exportError\" class=\"dou-dashboard__export-error\" data-dou-nodrag>\n <DouAlert tone=\"danger\" closable @close=\"frame.clearExportError(id)\">\n {{ exportError }}\n </DouAlert>\n </div>\n <WidgetBody\n v-if=\"active\"\n :widget=\"widget\"\n :type=\"type\"\n :editing=\"editing\"\n :messages=\"messages\"\n :set-props=\"frame.setProps\"\n :set-workbook=\"frame.setWorkbook\"\n />\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -27,8 +27,7 @@ var _hoisted_6 = {
|
|
|
27
27
|
class: "dou-dashboard__actions",
|
|
28
28
|
"data-dou-nodrag": ""
|
|
29
29
|
};
|
|
30
|
-
var _hoisted_7 = {
|
|
31
|
-
var _hoisted_8 = {
|
|
30
|
+
var _hoisted_7 = {
|
|
32
31
|
key: 2,
|
|
33
32
|
class: "dou-dashboard__export-error",
|
|
34
33
|
"data-dou-nodrag": ""
|
|
@@ -208,10 +207,9 @@ var widget_frame_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
|
|
|
208
207
|
})) : createCommentVNode("", true),
|
|
209
208
|
!editing.value && exporters.value.length ? (openBlock(), createBlock(unref(DouTooltip), {
|
|
210
209
|
key: 1,
|
|
211
|
-
content: messages.value.export
|
|
212
|
-
disabled: exportOpen.value
|
|
210
|
+
content: messages.value.export
|
|
213
211
|
}, {
|
|
214
|
-
default: withCtx(() => [
|
|
212
|
+
default: withCtx(() => [createVNode(unref(DouDropdown), {
|
|
215
213
|
open: exportOpen.value,
|
|
216
214
|
"onUpdate:open": _cache[2] || (_cache[2] = ($event) => exportOpen.value = $event),
|
|
217
215
|
placement: "bottom-end",
|
|
@@ -245,9 +243,9 @@ var widget_frame_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
|
|
|
245
243
|
"disabled"
|
|
246
244
|
])]),
|
|
247
245
|
_: 1
|
|
248
|
-
}, 8, ["open"])])
|
|
246
|
+
}, 8, ["open"])]),
|
|
249
247
|
_: 1
|
|
250
|
-
}, 8, ["content"
|
|
248
|
+
}, 8, ["content"])) : createCommentVNode("", true),
|
|
251
249
|
!editing.value && canFullscreen.value ? (openBlock(), createBlock(unref(DouTooltip), {
|
|
252
250
|
key: 2,
|
|
253
251
|
content: messages.value.fullscreen
|
|
@@ -267,7 +265,7 @@ var widget_frame_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
|
|
|
267
265
|
]),
|
|
268
266
|
_: 1
|
|
269
267
|
}, 8, ["as"])),
|
|
270
|
-
exportError.value ? (openBlock(), createElementBlock("div",
|
|
268
|
+
exportError.value ? (openBlock(), createElementBlock("div", _hoisted_7, [createVNode(unref(DouAlert), {
|
|
271
269
|
tone: "danger",
|
|
272
270
|
closable: "",
|
|
273
271
|
onClose: _cache[4] || (_cache[4] = ($event) => unref(frame).clearExportError(__props.id))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-frame.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle","_toDisplayString","_createCommentVNode","_createElementVNode","_createBlock","_resolveDynamicComponent","GridLayoutHandle","_withCtx","_unref","_createVNode","_createTextVNode","_createSlots","WidgetBody"],"sources":["../../src/dashboard/widget-frame.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DownloadIcon, MaximizeIcon, MoreHorizontalIcon } from '@dou-ui/icons'\nimport {\n DouAlert,\n DouButton,\n DouDropdown,\n DouDropdownItem,\n DouDropdownSub,\n DouEditable,\n DouTag,\n DouTooltip,\n} from 'dou-ui'\nimport type { DropdownValue } from 'dou-ui'\nimport { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport GridLayoutHandle from '../grid/grid-handle.vue'\nimport { format } from '../locale'\nimport { frameContextKey } from './frame-context'\nimport type { WidgetAction } from './frame-context'\nimport { observersKey } from './observers'\nimport WidgetBody from './widget-body.vue'\n\ndefineOptions({ name: 'DouDashboardWidget' })\n\nconst props = defineProps<{ id: string }>()\n\nconst frame = inject(frameContextKey)!\nconst widget = computed(() => frame.widget(props.id))\nconst type = computed(() => widget.value && frame.type(widget.value))\nconst title = computed(() => (widget.value ? frame.title(widget.value) : ''))\nconst editing = computed(() => frame.editing())\nconst messages = computed(() => frame.messages())\n/** The filters this widget set, each with a button to clear it. */\nconst linked = computed(() => frame.linked(props.id))\n/** All of them in one tag (a pivot table's click sets one per field), cleared together. */\nconst linkLabel = computed(() => linked.value.map((link) => link.label).join(' / '))\nfunction clearLinks() {\n for (const link of linked.value) frame.clearFilter(link.key)\n}\n\n/** Others at this widget, when editing together: an outline in the first one's color and their names. */\nconst peers = computed(() => frame.peers(props.id))\nconst peerText = (peer: { name: string; action: string }) => {\n const m = messages.value\n const text =\n peer.action === 'move'\n ? m.peerMoving\n : peer.action === 'resize'\n ? m.peerResizing\n : peer.action === 'settings'\n ? m.peerSettings\n : '{name}'\n return format(text, { name: peer.name })\n}\n\nconst renaming = ref(false)\n\n// Widgets far out of view show only their title until they come near: with\n// hundreds of widgets, their contents and controls are most of the mounting.\nconst root = ref<HTMLElement>()\nconst active = ref(frame.eager(props.id))\nconst observers = inject(observersKey)\nlet stop: (() => void) | undefined\nonMounted(() => {\n if (active.value || !observers) {\n active.value = true\n return\n }\n stop = observers.near(root.value!, () => {\n active.value = true\n stop?.()\n })\n})\nonBeforeUnmount(() => stop?.())\n// the dashboard draws everything for an export only when this widget isn't drawn yet\nwatch(active, (drawn) => frame.setDrawn(props.id, drawn), { immediate: true })\nonBeforeUnmount(() => frame.setDrawn(props.id, false))\n// drawn in full to export or print the dashboard, and kept that way\nwatch(\n () => frame.all(),\n (all) => {\n if (!all || active.value) return\n active.value = true\n stop?.()\n },\n { immediate: true },\n)\nconst canFullscreen = computed(() => type.value?.fullscreen !== false)\n\nconst emitAction = (action: WidgetAction) => frame.action(props.id, action)\n\n/** The file types this widget's content can be exported as; none unless it gives a workbook. */\nconst exporters = computed(() => frame.exporters(props.id))\nconst exportError = computed(() => frame.exportError(props.id))\nconst exporting = computed(() => frame.exporting(props.id))\nconst EXPORT = 'export:'\nconst exportOpen = ref(false)\n\nfunction onSelect(value: DropdownValue | undefined) {\n if (typeof value !== 'string') return\n if (value.startsWith(EXPORT)) frame.exportTo(props.id, value.slice(EXPORT.length))\n else emitAction(value as WidgetAction)\n}\n</script>\n\n<template>\n <!-- outside the frame, which cuts off what overflows it -->\n <div v-if=\"widget && peers.length\" class=\"dou-dashboard__peers\" aria-hidden=\"true\">\n <span\n v-for=\"peer in peers\"\n :key=\"`${peer.client}:${peer.action}`\"\n :class=\"['dou-dashboard__peer', `is-${peer.action}`]\"\n :style=\"{ '--dou-dashboard-peer-color': peer.color }\"\n >\n {{ peerText(peer) }}\n </span>\n </div>\n <div\n v-if=\"widget\"\n ref=\"root\"\n :class=\"['dou-dashboard__widget', peers.length && 'has-peers']\"\n :style=\"peers.length ? { '--dou-dashboard-peer-color': peers[0]!.color } : undefined\"\n >\n <template v-if=\"!active\">\n <div class=\"dou-dashboard__header\">\n <div class=\"dou-dashboard__title\">{{ title }}</div>\n </div>\n <div class=\"dou-dashboard__body\" />\n </template>\n <component\n v-else\n :is=\"editing ? GridLayoutHandle : 'div'\"\n :as=\"editing ? 'header' : undefined\"\n class=\"dou-dashboard__header\"\n >\n <DouEditable\n v-if=\"editing\"\n v-model:editing=\"renaming\"\n class=\"dou-dashboard__title\"\n :model-value=\"title\"\n trigger=\"dblclick\"\n select-on-edit\n :aria-label=\"messages.titleField\"\n :data-dou-nodrag=\"renaming ? '' : undefined\"\n @submit=\"(value) => frame.rename(id, value)\"\n />\n <div v-else class=\"dou-dashboard__title\">{{ title }}</div>\n <div v-if=\"linked.length\" class=\"dou-dashboard__links\" data-dou-nodrag>\n <DouTag\n size=\"sm\"\n closable\n :close-label=\"format(messages.clearFilter, { value: linkLabel })\"\n @close=\"clearLinks\"\n >\n {{ format(messages.filteredBy, { value: linkLabel }) }}\n </DouTag>\n </div>\n <div class=\"dou-dashboard__actions\" data-dou-nodrag>\n <DouDropdown v-if=\"editing\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton size=\"sm\" variant=\"ghost\" :aria-label=\"messages.widgetMenu\">\n <MoreHorizontalIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem value=\"settings\">{{ messages.settings }}</DouDropdownItem>\n <DouDropdownItem v-if=\"canFullscreen\" value=\"fullscreen\">\n {{ messages.fullscreen }}\n </DouDropdownItem>\n <DouDropdownSub v-if=\"exporters.length\" :title=\"messages.export\">\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n :disabled=\"exporting\"\n >\n <template v-if=\"exporter.icon\" #prefix><component :is=\"exporter.icon\" /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem value=\"duplicate\" shortcut=\"mod+d\">\n {{ messages.duplicate }}\n </DouDropdownItem>\n <DouDropdownItem value=\"remove\" tone=\"danger\" shortcut=\"delete\" divided>\n {{ messages.remove }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n <DouTooltip\n v-if=\"!editing && exporters.length\"\n :content=\"messages.export\"\n :disabled=\"exportOpen\"\n >\n <span class=\"dou-dashboard__trigger\">\n <DouDropdown v-model:open=\"exportOpen\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.export\"\n :loading=\"exporting\"\n :disabled=\"exporting\"\n >\n <DownloadIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n >\n <template v-if=\"exporter.icon\" #prefix\n ><component :is=\"exporter.icon\"\n /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n </span>\n </DouTooltip>\n <DouTooltip v-if=\"!editing && canFullscreen\" :content=\"messages.fullscreen\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.fullscreen\"\n @click=\"emitAction('fullscreen')\"\n >\n <MaximizeIcon />\n </DouButton>\n </DouTooltip>\n </div>\n </component>\n <div v-if=\"exportError\" class=\"dou-dashboard__export-error\" data-dou-nodrag>\n <DouAlert tone=\"danger\" closable @close=\"frame.clearExportError(id)\">\n {{ exportError }}\n </DouAlert>\n </div>\n <WidgetBody\n v-if=\"active\"\n :widget=\"widget\"\n :type=\"type\"\n :editing=\"editing\"\n :messages=\"messages\"\n :set-props=\"frame.setProps\"\n :set-workbook=\"frame.setWorkbook\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"widget-frame.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle","_toDisplayString","_createCommentVNode","_createElementVNode","_createBlock","_resolveDynamicComponent","GridLayoutHandle","_withCtx","_unref","_createVNode","_createTextVNode","_createSlots","WidgetBody"],"sources":["../../src/dashboard/widget-frame.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DownloadIcon, MaximizeIcon, MoreHorizontalIcon } from '@dou-ui/icons'\nimport {\n DouAlert,\n DouButton,\n DouDropdown,\n DouDropdownItem,\n DouDropdownSub,\n DouEditable,\n DouTag,\n DouTooltip,\n} from 'dou-ui'\nimport type { DropdownValue } from 'dou-ui'\nimport { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport GridLayoutHandle from '../grid/grid-handle.vue'\nimport { format } from '../locale'\nimport { frameContextKey } from './frame-context'\nimport type { WidgetAction } from './frame-context'\nimport { observersKey } from './observers'\nimport WidgetBody from './widget-body.vue'\n\ndefineOptions({ name: 'DouDashboardWidget' })\n\nconst props = defineProps<{ id: string }>()\n\nconst frame = inject(frameContextKey)!\nconst widget = computed(() => frame.widget(props.id))\nconst type = computed(() => widget.value && frame.type(widget.value))\nconst title = computed(() => (widget.value ? frame.title(widget.value) : ''))\nconst editing = computed(() => frame.editing())\nconst messages = computed(() => frame.messages())\n/** The filters this widget set, each with a button to clear it. */\nconst linked = computed(() => frame.linked(props.id))\n/** All of them in one tag (a pivot table's click sets one per field), cleared together. */\nconst linkLabel = computed(() => linked.value.map((link) => link.label).join(' / '))\nfunction clearLinks() {\n for (const link of linked.value) frame.clearFilter(link.key)\n}\n\n/** Others at this widget, when editing together: an outline in the first one's color and their names. */\nconst peers = computed(() => frame.peers(props.id))\nconst peerText = (peer: { name: string; action: string }) => {\n const m = messages.value\n const text =\n peer.action === 'move'\n ? m.peerMoving\n : peer.action === 'resize'\n ? m.peerResizing\n : peer.action === 'settings'\n ? m.peerSettings\n : '{name}'\n return format(text, { name: peer.name })\n}\n\nconst renaming = ref(false)\n\n// Widgets far out of view show only their title until they come near: with\n// hundreds of widgets, their contents and controls are most of the mounting.\nconst root = ref<HTMLElement>()\nconst active = ref(frame.eager(props.id))\nconst observers = inject(observersKey)\nlet stop: (() => void) | undefined\nonMounted(() => {\n if (active.value || !observers) {\n active.value = true\n return\n }\n stop = observers.near(root.value!, () => {\n active.value = true\n stop?.()\n })\n})\nonBeforeUnmount(() => stop?.())\n// the dashboard draws everything for an export only when this widget isn't drawn yet\nwatch(active, (drawn) => frame.setDrawn(props.id, drawn), { immediate: true })\nonBeforeUnmount(() => frame.setDrawn(props.id, false))\n// drawn in full to export or print the dashboard, and kept that way\nwatch(\n () => frame.all(),\n (all) => {\n if (!all || active.value) return\n active.value = true\n stop?.()\n },\n { immediate: true },\n)\nconst canFullscreen = computed(() => type.value?.fullscreen !== false)\n\nconst emitAction = (action: WidgetAction) => frame.action(props.id, action)\n\n/** The file types this widget's content can be exported as; none unless it gives a workbook. */\nconst exporters = computed(() => frame.exporters(props.id))\nconst exportError = computed(() => frame.exportError(props.id))\nconst exporting = computed(() => frame.exporting(props.id))\nconst EXPORT = 'export:'\nconst exportOpen = ref(false)\n\nfunction onSelect(value: DropdownValue | undefined) {\n if (typeof value !== 'string') return\n if (value.startsWith(EXPORT)) frame.exportTo(props.id, value.slice(EXPORT.length))\n else emitAction(value as WidgetAction)\n}\n</script>\n\n<template>\n <!-- outside the frame, which cuts off what overflows it -->\n <div v-if=\"widget && peers.length\" class=\"dou-dashboard__peers\" aria-hidden=\"true\">\n <span\n v-for=\"peer in peers\"\n :key=\"`${peer.client}:${peer.action}`\"\n :class=\"['dou-dashboard__peer', `is-${peer.action}`]\"\n :style=\"{ '--dou-dashboard-peer-color': peer.color }\"\n >\n {{ peerText(peer) }}\n </span>\n </div>\n <div\n v-if=\"widget\"\n ref=\"root\"\n :class=\"['dou-dashboard__widget', peers.length && 'has-peers']\"\n :style=\"peers.length ? { '--dou-dashboard-peer-color': peers[0]!.color } : undefined\"\n >\n <template v-if=\"!active\">\n <div class=\"dou-dashboard__header\">\n <div class=\"dou-dashboard__title\">{{ title }}</div>\n </div>\n <div class=\"dou-dashboard__body\" />\n </template>\n <component\n v-else\n :is=\"editing ? GridLayoutHandle : 'div'\"\n :as=\"editing ? 'header' : undefined\"\n class=\"dou-dashboard__header\"\n >\n <DouEditable\n v-if=\"editing\"\n v-model:editing=\"renaming\"\n class=\"dou-dashboard__title\"\n :model-value=\"title\"\n trigger=\"dblclick\"\n select-on-edit\n :aria-label=\"messages.titleField\"\n :data-dou-nodrag=\"renaming ? '' : undefined\"\n @submit=\"(value) => frame.rename(id, value)\"\n />\n <div v-else class=\"dou-dashboard__title\">{{ title }}</div>\n <div v-if=\"linked.length\" class=\"dou-dashboard__links\" data-dou-nodrag>\n <DouTag\n size=\"sm\"\n closable\n :close-label=\"format(messages.clearFilter, { value: linkLabel })\"\n @close=\"clearLinks\"\n >\n {{ format(messages.filteredBy, { value: linkLabel }) }}\n </DouTag>\n </div>\n <div class=\"dou-dashboard__actions\" data-dou-nodrag>\n <DouDropdown v-if=\"editing\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton size=\"sm\" variant=\"ghost\" :aria-label=\"messages.widgetMenu\">\n <MoreHorizontalIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem value=\"settings\">{{ messages.settings }}</DouDropdownItem>\n <DouDropdownItem v-if=\"canFullscreen\" value=\"fullscreen\">\n {{ messages.fullscreen }}\n </DouDropdownItem>\n <DouDropdownSub v-if=\"exporters.length\" :title=\"messages.export\">\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n :disabled=\"exporting\"\n >\n <template v-if=\"exporter.icon\" #prefix><component :is=\"exporter.icon\" /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </DouDropdownSub>\n <DouDropdownItem value=\"duplicate\" shortcut=\"mod+d\">\n {{ messages.duplicate }}\n </DouDropdownItem>\n <DouDropdownItem value=\"remove\" tone=\"danger\" shortcut=\"delete\" divided>\n {{ messages.remove }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n <DouTooltip v-if=\"!editing && exporters.length\" :content=\"messages.export\">\n <DouDropdown v-model:open=\"exportOpen\" placement=\"bottom-end\" @select=\"onSelect\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.export\"\n :loading=\"exporting\"\n :disabled=\"exporting\"\n >\n <DownloadIcon />\n </DouButton>\n <template #menu>\n <DouDropdownItem\n v-for=\"exporter in exporters\"\n :key=\"exporter.name\"\n :value=\"EXPORT + exporter.name\"\n >\n <template v-if=\"exporter.icon\" #prefix><component :is=\"exporter.icon\" /></template>\n {{ exporter.label }}\n </DouDropdownItem>\n </template>\n </DouDropdown>\n </DouTooltip>\n <DouTooltip v-if=\"!editing && canFullscreen\" :content=\"messages.fullscreen\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n :aria-label=\"messages.fullscreen\"\n @click=\"emitAction('fullscreen')\"\n >\n <MaximizeIcon />\n </DouButton>\n </DouTooltip>\n </div>\n </component>\n <div v-if=\"exportError\" class=\"dou-dashboard__export-error\" data-dou-nodrag>\n <DouAlert tone=\"danger\" closable @close=\"frame.clearExportError(id)\">\n {{ exportError }}\n </DouAlert>\n </div>\n <WidgetBody\n v-if=\"active\"\n :widget=\"widget\"\n :type=\"type\"\n :editing=\"editing\"\n :messages=\"messages\"\n :set-props=\"frame.setProps\"\n :set-workbook=\"frame.setWorkbook\"\n />\n </div>\n</template>\n"],"mappings":"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"}
|
package/dist/layout/engine.js
CHANGED
|
@@ -238,10 +238,157 @@ function findPlace(items, size, options) {
|
|
|
238
238
|
};
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
241
|
+
* Whether a row came out right: every item at least a column wide, none
|
|
242
|
+
* on top of the one before it or past the last column, and items that
|
|
243
|
+
* were equally wide still equally wide.
|
|
244
|
+
*/
|
|
245
|
+
function fair(spans, to) {
|
|
246
|
+
const widths = /* @__PURE__ */ new Map();
|
|
247
|
+
return spans.every((span, i) => {
|
|
248
|
+
const prev = spans[i - 1];
|
|
249
|
+
if (span.w < 1 || span.x + span.w > to) return false;
|
|
250
|
+
if (prev && prev.line === span.line && span.x < prev.x + prev.w) return false;
|
|
251
|
+
const w = widths.get(span.item.w);
|
|
252
|
+
if (w === void 0) widths.set(span.item.w, span.w);
|
|
253
|
+
return w === void 0 || w === span.w;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/** Both edges scaled and rounded, so items side by side stay side by side. */
|
|
257
|
+
function scaled(row, factor) {
|
|
258
|
+
const edge = (value) => Math.round(value * factor);
|
|
259
|
+
return row.map((item) => {
|
|
260
|
+
const x = edge(item.x);
|
|
261
|
+
return {
|
|
262
|
+
item,
|
|
263
|
+
x,
|
|
264
|
+
w: edge(item.x + item.w) - x,
|
|
265
|
+
line: 0,
|
|
266
|
+
factor
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The row wrapped onto as few lines as keep its items equally wide, at
|
|
272
|
+
* most `most`. Items are packed left to right without the gaps between
|
|
273
|
+
* them, each line holding the same number of source columns at most, the
|
|
274
|
+
* fullest line filling the grid. At least one line holds two items or
|
|
275
|
+
* more, so items never end up one per line. Widths are rounded down,
|
|
276
|
+
* leaving columns empty, when no number of lines keeps them equal otherwise.
|
|
277
|
+
*/
|
|
278
|
+
function wrapped(row, to, most) {
|
|
279
|
+
const total = row.reduce((sum, item) => sum + item.w, 0);
|
|
280
|
+
const pack = (size) => {
|
|
281
|
+
const lines = [];
|
|
282
|
+
let used = Infinity;
|
|
283
|
+
for (const item of row) {
|
|
284
|
+
if (used + item.w > size) {
|
|
285
|
+
lines.push([]);
|
|
286
|
+
used = 0;
|
|
287
|
+
}
|
|
288
|
+
lines[lines.length - 1].push(item);
|
|
289
|
+
used += item.w;
|
|
290
|
+
}
|
|
291
|
+
return lines;
|
|
292
|
+
};
|
|
293
|
+
const options = /* @__PURE__ */ new Map();
|
|
294
|
+
for (let size = Math.max(...row.map((item) => item.w)); size < total; size++) {
|
|
295
|
+
const lines = pack(size);
|
|
296
|
+
if (lines.length <= most && lines.length < row.length && !options.has(lines.length)) options.set(lines.length, {
|
|
297
|
+
lines,
|
|
298
|
+
size
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
const counts = [...options.keys()];
|
|
302
|
+
counts.sort((a, b) => a - b);
|
|
303
|
+
for (const down of [false, true]) for (const count of counts) {
|
|
304
|
+
const { lines, size } = options.get(count);
|
|
305
|
+
const factor = to / size;
|
|
306
|
+
const spans = [];
|
|
307
|
+
for (const [line, items] of lines.entries()) {
|
|
308
|
+
let start = 0;
|
|
309
|
+
let end = 0;
|
|
310
|
+
for (const item of items) {
|
|
311
|
+
const x = down ? end : Math.round(start * factor);
|
|
312
|
+
start += item.w;
|
|
313
|
+
const w = down ? Math.floor(item.w * factor) : Math.round(start * factor) - x;
|
|
314
|
+
end = x + w;
|
|
315
|
+
spans.push({
|
|
316
|
+
item,
|
|
317
|
+
x,
|
|
318
|
+
w,
|
|
319
|
+
line,
|
|
320
|
+
factor
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (fair(spans, to)) return spans;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* The row kept on one line, items that share a width given the same
|
|
329
|
+
* number of columns: rounded to the nearest when they fit, otherwise
|
|
330
|
+
* rounded down. Items that touched still touch, so the columns left empty
|
|
331
|
+
* gather at the end; items with a gap between them stay near where they
|
|
332
|
+
* were, moved left only as far as it takes to fit.
|
|
333
|
+
*/
|
|
334
|
+
function oneLine(row, scale, to) {
|
|
335
|
+
const shared = /* @__PURE__ */ new Map();
|
|
336
|
+
for (const item of row) shared.set(item.w, (shared.get(item.w) ?? 0) + 1);
|
|
337
|
+
for (const round of [Math.round, Math.floor]) {
|
|
338
|
+
const spans = [];
|
|
339
|
+
for (const item of row) {
|
|
340
|
+
const prev = spans[spans.length - 1];
|
|
341
|
+
const x = !prev ? Math.round(item.x * scale) : prev.item.x + prev.item.w === item.x ? prev.x + prev.w : Math.max(Math.round(item.x * scale), prev.x + prev.w);
|
|
342
|
+
const w = (shared.get(item.w) > 1 ? round : Math.round)(item.w * scale);
|
|
343
|
+
spans.push({
|
|
344
|
+
item,
|
|
345
|
+
x,
|
|
346
|
+
w,
|
|
347
|
+
line: 0,
|
|
348
|
+
factor: scale
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
let end = to;
|
|
352
|
+
for (let i = spans.length - 1; i >= 0; i--) {
|
|
353
|
+
const span = spans[i];
|
|
354
|
+
span.x = Math.min(span.x, end - span.w);
|
|
355
|
+
end = span.x;
|
|
356
|
+
}
|
|
357
|
+
if (end >= 0 && fair(spans, to)) return spans;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* One row (items sharing a `y`, left to right) on `to` columns, keeping
|
|
362
|
+
* equally wide items equally wide. In order of preference: scaled as is;
|
|
363
|
+
* wrapped onto two lines; kept on one line; wrapped onto more lines. The
|
|
364
|
+
* widths are rounded to the nearest column when that keeps them equal and
|
|
365
|
+
* rounded down otherwise, leaving columns empty. Rows
|
|
366
|
+
* only wrap when the grid gets narrower and the row is a band of its own
|
|
367
|
+
* (all its items equally tall, nothing else reaching into it). Rounded as
|
|
368
|
+
* before when none of that works.
|
|
369
|
+
*/
|
|
370
|
+
function scaleRow(row, band, from, to) {
|
|
371
|
+
const scale = to / from;
|
|
372
|
+
const spans = scaled(row, scale);
|
|
373
|
+
if (fair(spans, to)) return spans;
|
|
374
|
+
const wraps = band && to < from;
|
|
375
|
+
const two = wraps ? wrapped(row, to, 2) : void 0;
|
|
376
|
+
if (two) return two;
|
|
377
|
+
const one = oneLine(row, scale, to);
|
|
378
|
+
if (one) return one;
|
|
379
|
+
return (wraps ? wrapped(row, to, row.length) : void 0) ?? spans.map((span) => ({
|
|
380
|
+
...span,
|
|
381
|
+
w: Math.max(1, span.w)
|
|
382
|
+
}));
|
|
383
|
+
}
|
|
384
|
+
/** A `minW` or `maxW` scaled with the item. */
|
|
385
|
+
var limit = (value, factor) => value === void 0 ? void 0 : Math.max(1, Math.round(value * factor));
|
|
386
|
+
/**
|
|
241
387
|
* The layout worked out for a grid of another width: positions and widths
|
|
242
|
-
* scaled by the ratio of the columns, then settled.
|
|
243
|
-
*
|
|
244
|
-
*
|
|
388
|
+
* scaled by the ratio of the columns, then settled. Items in a row that
|
|
389
|
+
* were equally wide stay equally wide, by wrapping the row or leaving
|
|
390
|
+
* columns empty (see the docs). On a single column the items are stacked
|
|
391
|
+
* in reading order (top to bottom, then left to right), each keeping its height.
|
|
245
392
|
*/
|
|
246
393
|
function deriveLayout(items, from, options) {
|
|
247
394
|
const to = options.columns;
|
|
@@ -265,19 +412,32 @@ function deriveLayout(items, from, options) {
|
|
|
265
412
|
}
|
|
266
413
|
return out;
|
|
267
414
|
}
|
|
268
|
-
const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
415
|
+
const rows = /* @__PURE__ */ new Map();
|
|
416
|
+
for (const item of items) {
|
|
417
|
+
const row = rows.get(item.y);
|
|
418
|
+
if (row) row.push(item);
|
|
419
|
+
else rows.set(item.y, [item]);
|
|
420
|
+
}
|
|
421
|
+
const ys = [...rows.keys()];
|
|
422
|
+
ys.sort((a, b) => a - b);
|
|
423
|
+
const placed = /* @__PURE__ */ new Map();
|
|
424
|
+
let shift = 0;
|
|
425
|
+
for (const y of ys) {
|
|
426
|
+
const row = rows.get(y);
|
|
427
|
+
row.sort((a, b) => a.x - b.x);
|
|
428
|
+
const h = row[0].h;
|
|
429
|
+
const spans = scaleRow(row, row.every((item) => item.h === h) && items.every((item) => item.y === y || item.y + item.h <= y || item.y >= y + h), from, to);
|
|
430
|
+
for (const span of spans) placed.set(span.item, fitItem({
|
|
431
|
+
...span.item,
|
|
432
|
+
x: span.x,
|
|
433
|
+
y: y + shift + span.line * h,
|
|
434
|
+
w: span.w,
|
|
435
|
+
minW: limit(span.item.minW, span.factor),
|
|
436
|
+
maxW: limit(span.item.maxW, span.factor)
|
|
437
|
+
}, to));
|
|
438
|
+
shift += spans[spans.length - 1].line * h;
|
|
439
|
+
}
|
|
440
|
+
return normalizeLayout(items.map((item) => placed.get(item)), options);
|
|
281
441
|
}
|
|
282
442
|
export { compactLayout, deriveLayout, findPlace, fitItem, layoutHeight, moveItem, moveItemBy, normalizeLayout, overlaps, resizeItem, resizeItemBy };
|
|
283
443
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","names":[],"sources":["../../src/layout/engine.ts"],"sourcesContent":["import type { GridItem, GridLayoutOptions, GridPosition, GridSize } from './types'\n\n/*\n * The layout engine: plain functions from a layout to a layout.\n *\n * Every function returns a new array in the same order as the one it was\n * given, and keeps the objects of the items that did not move, so a caller\n * can tell what changed by identity. The same input always gives the same\n * output: the order items are settled in depends only on their positions\n * and their places in the array, which is what lets several people editing\n * the same layout end up with the same result.\n */\n\ntype Box = Pick<GridItem, 'x' | 'y' | 'w' | 'h'>\n\n/** Whether two boxes share at least one cell. */\nexport function overlaps(a: Box, b: Box): boolean {\n return a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h\n}\n\n/** The row just below the lowest item: how many rows the layout takes up. */\nexport function layoutHeight(items: readonly Box[]): number {\n let bottom = 0\n for (const item of items) bottom = Math.max(bottom, item.y + item.h)\n return bottom\n}\n\nconst int = (value: number, fallback: number) =>\n Number.isFinite(value) ? Math.round(value) : fallback\n\n/** The width an item may have on a grid of `columns`. */\nfunction clampW(item: GridItem, w: number, columns: number) {\n const max = Math.min(columns, item.maxW ?? columns)\n const min = Math.min(max, Math.max(1, item.minW ?? 1))\n return Math.min(max, Math.max(min, int(w, min)))\n}\n\nfunction clampH(item: GridItem, h: number) {\n const max = Math.max(1, item.maxH ?? Infinity)\n const min = Math.min(max, Math.max(1, item.minH ?? 1))\n return Math.min(max, Math.max(min, int(h, min)))\n}\n\n/**\n * The item with its size inside its limits and the grid's width, and its\n * position on the grid, in whole cells. Returns the item itself when it fits.\n */\nexport function fitItem(item: GridItem, columns: number): GridItem {\n const w = clampW(item, item.w, columns)\n const h = clampH(item, item.h)\n const x = Math.min(columns - w, Math.max(0, int(item.x, 0)))\n const y = Math.max(0, int(item.y, 0))\n return x === item.x && y === item.y && w === item.w && h === item.h\n ? item\n : { ...item, x, y, w, h }\n}\n\nconst at = (item: GridItem, x: number, y: number): GridItem =>\n item.x === x && item.y === y ? item : { ...item, x, y }\n\n/**\n * Where an item the moved one landed on could step aside to: the same\n * row, shifted into the columns the moved item left. This is what turns\n * dropping an item onto its neighbour into a swap, instead of pushing the\n * neighbour down. `undefined` when the item isn't in the way, or wouldn't\n * fit in those columns.\n */\nfunction aside(item: GridItem, fixed?: GridItem, origin?: Box): number | undefined {\n if (!fixed || !origin || !overlaps(item, fixed)) return undefined\n const hi = origin.x + origin.w - item.w\n if (hi < origin.x) return undefined\n const x = Math.min(hi, Math.max(origin.x, item.x))\n return x === item.x ? undefined : x\n}\n\n/** The first of `boxes` that shares a cell with the box, if any. */\nfunction hit(boxes: readonly Box[], box: Box): Box | undefined {\n for (const other of boxes) if (overlaps(other, box)) return other\n return undefined\n}\n\n/** Moves the box down until it is clear of every one of `boxes`; returns its row. */\nfunction below(boxes: readonly Box[], box: Box): number {\n const probe = { ...box }\n for (let other = hit(boxes, probe); other; other = hit(boxes, probe)) probe.y = other.y + other.h\n return probe.y\n}\n\n/**\n * Settles every item that isn't locked and isn't `fixed`; those stay where\n * they are and the rest go around them. Items are settled from the top\n * down (then left to right, then by their place in the array).\n */\nfunction settle(\n items: readonly GridItem[],\n options: GridLayoutOptions,\n fixed?: GridItem,\n origin?: Box,\n): GridItem[] {\n const out = items.slice()\n const obstacles: GridItem[] = []\n const order: number[] = []\n items.forEach((item, i) => {\n if (item.locked || item === fixed) obstacles.push(item)\n else order.push(i)\n })\n order.sort((a, b) => items[a]!.y - items[b]!.y || items[a]!.x - items[b]!.x || a - b)\n\n if (options.compact === false) {\n // Each item keeps its row unless something settled before it is in the way.\n const placed = obstacles.slice()\n for (const i of order) {\n const item = items[i]!\n let x = item.x\n let y = below(placed, item)\n const side = aside(item, fixed, origin)\n if (side !== undefined && !hit(placed, { ...item, x: side })) [x, y] = [side, item.y]\n placed.push((out[i] = at(item, x, y)))\n }\n return out\n }\n\n // `top[c]` is the row below everything settled so far in column `c`: an\n // item can float up to the lowest of these across its columns, which is\n // as far as it can go without passing an item that was above it.\n const top = new Int32Array(options.columns)\n for (const i of order) {\n const item = items[i]!\n const rise = (x: number) => {\n let y = 0\n for (let c = x; c < x + item.w; c++) y = Math.max(y, top[c] ?? 0)\n return below(obstacles, { x, y, w: item.w, h: item.h })\n }\n let x = item.x\n let y = rise(x)\n const side = aside(item, fixed, origin)\n if (side !== undefined) {\n const y2 = rise(side)\n if (y2 < y) [x, y] = [side, y2]\n }\n for (let c = x; c < x + item.w; c++) top[c] = y + item.h\n out[i] = at(item, x, y)\n }\n return out\n}\n\n/**\n * The layout fitted to the grid: sizes inside their limits, nothing past\n * the last column, no two items on the same cell and, when compacting,\n * no gaps above items. Returns `items` itself when it is already settled.\n */\nexport function normalizeLayout(\n items: readonly GridItem[],\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const fitted = items.map((item) => fitItem(item, options.columns))\n const out = settle(fitted, options)\n return out.every((item, i) => item === items[i]) ? items : out\n}\n\n/** Floats every item up as far as it goes (ignores `compact`). */\nexport function compactLayout(items: readonly GridItem[], columns: number): GridItem[] {\n return settle(items, { columns, compact: 'vertical' })\n}\n\n/** Puts `item` at the given place, moved down below any locked item it lands on. */\nfunction place(\n items: readonly GridItem[],\n index: number,\n next: GridItem,\n options: GridLayoutOptions,\n): GridItem[] {\n const locked = items.filter((other) => other.locked && other !== items[index])\n const y = below(locked, next)\n const out = items.slice()\n const moved = (out[index] = at(next, next.x, y))\n const settled = settle(out, options, moved, items[index])\n // Compacting a second time lets the item itself float up into the gap\n // it would otherwise leave, and puts it after the items it was dropped below.\n return options.compact === false ? settled : settle(settled, options)\n}\n\n/**\n * Moves an item to a cell; the items it lands on make way. Locked items\n * and unknown ids leave the layout as it is.\n */\nexport function moveItem(\n items: readonly GridItem[],\n id: string,\n to: GridPosition,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const index = items.findIndex((item) => item.id === id)\n const item = items[index]\n if (!item || item.locked) return items\n const x = Math.min(options.columns - item.w, Math.max(0, int(to.x, item.x)))\n const y = Math.max(0, int(to.y, item.y))\n return place(items, index, { ...item, x, y }, options)\n}\n\n/**\n * Gives an item a new size, keeping its top-left corner; the items it now\n * covers make way. A size that would cover a locked item is refused.\n */\nexport function resizeItem(\n items: readonly GridItem[],\n id: string,\n to: GridSize,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const index = items.findIndex((item) => item.id === id)\n const item = items[index]\n if (!item || item.locked) return items\n const w = Math.min(options.columns - item.x, clampW(item, to.w, options.columns))\n const h = clampH(item, to.h)\n const next = { ...item, w: Math.max(1, w), h }\n if (items.some((other) => other.locked && other !== item && overlaps(other, next))) return items\n return place(items, index, next, options)\n}\n\nconst sameSpot = (a: GridItem | undefined, b: GridItem) =>\n !!a && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h\n\n/**\n * Moves an item by whole cells, as the arrow keys do. Moving up or down\n * goes on past rows where the item would only settle back where it was,\n * so one press always moves it, to the next place it can take.\n */\nexport function moveItemBy(\n items: readonly GridItem[],\n id: string,\n dx: number,\n dy: number,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const item = items.find((other) => other.id === id)\n if (!item || item.locked) return items\n if (!dy) return moveItem(items, id, { x: item.x + dx, y: item.y }, options)\n const step = Math.sign(dy)\n const last = layoutHeight(items)\n for (let y = item.y + dy; y >= 0 && y <= last; y += step) {\n const out = moveItem(items, id, { x: item.x + dx, y }, options)\n if (\n !sameSpot(\n out.find((other) => other.id === id),\n item,\n )\n )\n return out\n }\n return items\n}\n\n/** Resizes an item by whole cells, as Shift and the arrow keys do. */\nexport function resizeItemBy(\n items: readonly GridItem[],\n id: string,\n dw: number,\n dh: number,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const item = items.find((other) => other.id === id)\n if (!item) return items\n return resizeItem(items, id, { w: item.w + dw, h: item.h + dh }, options)\n}\n\n/**\n * Where a new item of `size` fits: the first free spot reading from the top\n * left, or below everything when no row has room.\n */\nexport function findPlace(\n items: readonly GridItem[],\n size: GridSize,\n options: GridLayoutOptions,\n): GridPosition {\n const w = Math.min(options.columns, Math.max(1, Math.round(size.w)))\n const h = Math.max(1, Math.round(size.h))\n const bottom = layoutHeight(items)\n for (let y = 0; y < bottom; y++)\n for (let x = 0; x + w <= options.columns; x++) {\n const other = hit(items, { x, y, w, h })\n if (!other) return { x, y }\n // skip to the column after the item in the way\n x = other.x + other.w - 1\n }\n return { x: 0, y: bottom }\n}\n\n/**\n * The layout worked out for a grid of another width: positions and widths\n * scaled by the ratio of the columns, then settled. On a single column the\n * items are stacked in reading order (top to bottom, then left to right),\n * each keeping its height.\n */\nexport function deriveLayout(\n items: readonly GridItem[],\n from: number,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const to = options.columns\n if (from === to) return normalizeLayout(items, options)\n if (to === 1) {\n const order = items.map((_, i) => i)\n order.sort((a, b) => items[a]!.y - items[b]!.y || items[a]!.x - items[b]!.x || a - b)\n const out = items.slice()\n let y = 0\n for (const i of order) {\n const item = fitItem({ ...items[i]!, x: 0, w: 1 }, 1)\n out[i] = { ...item, y }\n y += item.h\n }\n return out\n }\n const scale = to / from\n // both edges are scaled, so items side by side stay side by side\n const edge = (value: number) => Math.round(value * scale)\n const limit = (value: number | undefined) =>\n value === undefined ? undefined : Math.max(1, edge(value))\n const scaled = items.map((item) => {\n const x = edge(item.x)\n return fitItem(\n {\n ...item,\n x,\n w: Math.max(1, edge(item.x + item.w) - x),\n minW: limit(item.minW),\n maxW: limit(item.maxW),\n },\n to,\n )\n })\n return normalizeLayout(scaled, options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"engine.js","names":[],"sources":["../../src/layout/engine.ts"],"sourcesContent":["import type { GridItem, GridLayoutOptions, GridPosition, GridSize } from './types'\n\n/*\n * The layout engine: plain functions from a layout to a layout.\n *\n * Every function returns a new array in the same order as the one it was\n * given, and keeps the objects of the items that did not move, so a caller\n * can tell what changed by identity. The same input always gives the same\n * output: the order items are settled in depends only on their positions\n * and their places in the array, which is what lets several people editing\n * the same layout end up with the same result.\n */\n\ntype Box = Pick<GridItem, 'x' | 'y' | 'w' | 'h'>\n\n/** Whether two boxes share at least one cell. */\nexport function overlaps(a: Box, b: Box): boolean {\n return a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h\n}\n\n/** The row just below the lowest item: how many rows the layout takes up. */\nexport function layoutHeight(items: readonly Box[]): number {\n let bottom = 0\n for (const item of items) bottom = Math.max(bottom, item.y + item.h)\n return bottom\n}\n\nconst int = (value: number, fallback: number) =>\n Number.isFinite(value) ? Math.round(value) : fallback\n\n/** The width an item may have on a grid of `columns`. */\nfunction clampW(item: GridItem, w: number, columns: number) {\n const max = Math.min(columns, item.maxW ?? columns)\n const min = Math.min(max, Math.max(1, item.minW ?? 1))\n return Math.min(max, Math.max(min, int(w, min)))\n}\n\nfunction clampH(item: GridItem, h: number) {\n const max = Math.max(1, item.maxH ?? Infinity)\n const min = Math.min(max, Math.max(1, item.minH ?? 1))\n return Math.min(max, Math.max(min, int(h, min)))\n}\n\n/**\n * The item with its size inside its limits and the grid's width, and its\n * position on the grid, in whole cells. Returns the item itself when it fits.\n */\nexport function fitItem(item: GridItem, columns: number): GridItem {\n const w = clampW(item, item.w, columns)\n const h = clampH(item, item.h)\n const x = Math.min(columns - w, Math.max(0, int(item.x, 0)))\n const y = Math.max(0, int(item.y, 0))\n return x === item.x && y === item.y && w === item.w && h === item.h\n ? item\n : { ...item, x, y, w, h }\n}\n\nconst at = (item: GridItem, x: number, y: number): GridItem =>\n item.x === x && item.y === y ? item : { ...item, x, y }\n\n/**\n * Where an item the moved one landed on could step aside to: the same\n * row, shifted into the columns the moved item left. This is what turns\n * dropping an item onto its neighbour into a swap, instead of pushing the\n * neighbour down. `undefined` when the item isn't in the way, or wouldn't\n * fit in those columns.\n */\nfunction aside(item: GridItem, fixed?: GridItem, origin?: Box): number | undefined {\n if (!fixed || !origin || !overlaps(item, fixed)) return undefined\n const hi = origin.x + origin.w - item.w\n if (hi < origin.x) return undefined\n const x = Math.min(hi, Math.max(origin.x, item.x))\n return x === item.x ? undefined : x\n}\n\n/** The first of `boxes` that shares a cell with the box, if any. */\nfunction hit(boxes: readonly Box[], box: Box): Box | undefined {\n for (const other of boxes) if (overlaps(other, box)) return other\n return undefined\n}\n\n/** Moves the box down until it is clear of every one of `boxes`; returns its row. */\nfunction below(boxes: readonly Box[], box: Box): number {\n const probe = { ...box }\n for (let other = hit(boxes, probe); other; other = hit(boxes, probe)) probe.y = other.y + other.h\n return probe.y\n}\n\n/**\n * Settles every item that isn't locked and isn't `fixed`; those stay where\n * they are and the rest go around them. Items are settled from the top\n * down (then left to right, then by their place in the array).\n */\nfunction settle(\n items: readonly GridItem[],\n options: GridLayoutOptions,\n fixed?: GridItem,\n origin?: Box,\n): GridItem[] {\n const out = items.slice()\n const obstacles: GridItem[] = []\n const order: number[] = []\n items.forEach((item, i) => {\n if (item.locked || item === fixed) obstacles.push(item)\n else order.push(i)\n })\n order.sort((a, b) => items[a]!.y - items[b]!.y || items[a]!.x - items[b]!.x || a - b)\n\n if (options.compact === false) {\n // Each item keeps its row unless something settled before it is in the way.\n const placed = obstacles.slice()\n for (const i of order) {\n const item = items[i]!\n let x = item.x\n let y = below(placed, item)\n const side = aside(item, fixed, origin)\n if (side !== undefined && !hit(placed, { ...item, x: side })) [x, y] = [side, item.y]\n placed.push((out[i] = at(item, x, y)))\n }\n return out\n }\n\n // `top[c]` is the row below everything settled so far in column `c`: an\n // item can float up to the lowest of these across its columns, which is\n // as far as it can go without passing an item that was above it.\n const top = new Int32Array(options.columns)\n for (const i of order) {\n const item = items[i]!\n const rise = (x: number) => {\n let y = 0\n for (let c = x; c < x + item.w; c++) y = Math.max(y, top[c] ?? 0)\n return below(obstacles, { x, y, w: item.w, h: item.h })\n }\n let x = item.x\n let y = rise(x)\n const side = aside(item, fixed, origin)\n if (side !== undefined) {\n const y2 = rise(side)\n if (y2 < y) [x, y] = [side, y2]\n }\n for (let c = x; c < x + item.w; c++) top[c] = y + item.h\n out[i] = at(item, x, y)\n }\n return out\n}\n\n/**\n * The layout fitted to the grid: sizes inside their limits, nothing past\n * the last column, no two items on the same cell and, when compacting,\n * no gaps above items. Returns `items` itself when it is already settled.\n */\nexport function normalizeLayout(\n items: readonly GridItem[],\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const fitted = items.map((item) => fitItem(item, options.columns))\n const out = settle(fitted, options)\n return out.every((item, i) => item === items[i]) ? items : out\n}\n\n/** Floats every item up as far as it goes (ignores `compact`). */\nexport function compactLayout(items: readonly GridItem[], columns: number): GridItem[] {\n return settle(items, { columns, compact: 'vertical' })\n}\n\n/** Puts `item` at the given place, moved down below any locked item it lands on. */\nfunction place(\n items: readonly GridItem[],\n index: number,\n next: GridItem,\n options: GridLayoutOptions,\n): GridItem[] {\n const locked = items.filter((other) => other.locked && other !== items[index])\n const y = below(locked, next)\n const out = items.slice()\n const moved = (out[index] = at(next, next.x, y))\n const settled = settle(out, options, moved, items[index])\n // Compacting a second time lets the item itself float up into the gap\n // it would otherwise leave, and puts it after the items it was dropped below.\n return options.compact === false ? settled : settle(settled, options)\n}\n\n/**\n * Moves an item to a cell; the items it lands on make way. Locked items\n * and unknown ids leave the layout as it is.\n */\nexport function moveItem(\n items: readonly GridItem[],\n id: string,\n to: GridPosition,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const index = items.findIndex((item) => item.id === id)\n const item = items[index]\n if (!item || item.locked) return items\n const x = Math.min(options.columns - item.w, Math.max(0, int(to.x, item.x)))\n const y = Math.max(0, int(to.y, item.y))\n return place(items, index, { ...item, x, y }, options)\n}\n\n/**\n * Gives an item a new size, keeping its top-left corner; the items it now\n * covers make way. A size that would cover a locked item is refused.\n */\nexport function resizeItem(\n items: readonly GridItem[],\n id: string,\n to: GridSize,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const index = items.findIndex((item) => item.id === id)\n const item = items[index]\n if (!item || item.locked) return items\n const w = Math.min(options.columns - item.x, clampW(item, to.w, options.columns))\n const h = clampH(item, to.h)\n const next = { ...item, w: Math.max(1, w), h }\n if (items.some((other) => other.locked && other !== item && overlaps(other, next))) return items\n return place(items, index, next, options)\n}\n\nconst sameSpot = (a: GridItem | undefined, b: GridItem) =>\n !!a && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h\n\n/**\n * Moves an item by whole cells, as the arrow keys do. Moving up or down\n * goes on past rows where the item would only settle back where it was,\n * so one press always moves it, to the next place it can take.\n */\nexport function moveItemBy(\n items: readonly GridItem[],\n id: string,\n dx: number,\n dy: number,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const item = items.find((other) => other.id === id)\n if (!item || item.locked) return items\n if (!dy) return moveItem(items, id, { x: item.x + dx, y: item.y }, options)\n const step = Math.sign(dy)\n const last = layoutHeight(items)\n for (let y = item.y + dy; y >= 0 && y <= last; y += step) {\n const out = moveItem(items, id, { x: item.x + dx, y }, options)\n if (\n !sameSpot(\n out.find((other) => other.id === id),\n item,\n )\n )\n return out\n }\n return items\n}\n\n/** Resizes an item by whole cells, as Shift and the arrow keys do. */\nexport function resizeItemBy(\n items: readonly GridItem[],\n id: string,\n dw: number,\n dh: number,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const item = items.find((other) => other.id === id)\n if (!item) return items\n return resizeItem(items, id, { w: item.w + dw, h: item.h + dh }, options)\n}\n\n/**\n * Where a new item of `size` fits: the first free spot reading from the top\n * left, or below everything when no row has room.\n */\nexport function findPlace(\n items: readonly GridItem[],\n size: GridSize,\n options: GridLayoutOptions,\n): GridPosition {\n const w = Math.min(options.columns, Math.max(1, Math.round(size.w)))\n const h = Math.max(1, Math.round(size.h))\n const bottom = layoutHeight(items)\n for (let y = 0; y < bottom; y++)\n for (let x = 0; x + w <= options.columns; x++) {\n const other = hit(items, { x, y, w, h })\n if (!other) return { x, y }\n // skip to the column after the item in the way\n x = other.x + other.w - 1\n }\n return { x: 0, y: bottom }\n}\n\ninterface Span {\n item: GridItem\n x: number\n w: number\n /** Line within the row, 0 when the row didn't wrap. */\n line: number\n /** What the item's width was scaled by, for its `minW` and `maxW`. */\n factor: number\n}\n\n/**\n * Whether a row came out right: every item at least a column wide, none\n * on top of the one before it or past the last column, and items that\n * were equally wide still equally wide.\n */\nfunction fair(spans: readonly Span[], to: number) {\n const widths = new Map<number, number>()\n return spans.every((span, i) => {\n const prev = spans[i - 1]\n if (span.w < 1 || span.x + span.w > to) return false\n if (prev && prev.line === span.line && span.x < prev.x + prev.w) return false\n const w = widths.get(span.item.w)\n if (w === undefined) widths.set(span.item.w, span.w)\n return w === undefined || w === span.w\n })\n}\n\n/** Both edges scaled and rounded, so items side by side stay side by side. */\nfunction scaled(row: readonly GridItem[], factor: number): Span[] {\n const edge = (value: number) => Math.round(value * factor)\n return row.map((item) => {\n const x = edge(item.x)\n return { item, x, w: edge(item.x + item.w) - x, line: 0, factor }\n })\n}\n\n/**\n * The row wrapped onto as few lines as keep its items equally wide, at\n * most `most`. Items are packed left to right without the gaps between\n * them, each line holding the same number of source columns at most, the\n * fullest line filling the grid. At least one line holds two items or\n * more, so items never end up one per line. Widths are rounded down,\n * leaving columns empty, when no number of lines keeps them equal otherwise.\n */\nfunction wrapped(row: readonly GridItem[], to: number, most: number): Span[] | undefined {\n const total = row.reduce((sum, item) => sum + item.w, 0)\n const pack = (size: number) => {\n const lines: GridItem[][] = []\n let used = Infinity\n for (const item of row) {\n if (used + item.w > size) {\n lines.push([])\n used = 0\n }\n lines[lines.length - 1]!.push(item)\n used += item.w\n }\n return lines\n }\n // the smallest size for each number of lines balances the lines best\n const options = new Map<number, { lines: GridItem[][]; size: number }>()\n for (let size = Math.max(...row.map((item) => item.w)); size < total; size++) {\n const lines = pack(size)\n if (lines.length <= most && lines.length < row.length && !options.has(lines.length))\n options.set(lines.length, { lines, size })\n }\n const counts = [...options.keys()]\n counts.sort((a, b) => a - b)\n for (const down of [false, true])\n for (const count of counts) {\n const { lines, size } = options.get(count)!\n const factor = to / size\n const spans: Span[] = []\n for (const [line, items] of lines.entries()) {\n let start = 0\n let end = 0\n for (const item of items) {\n const x = down ? end : Math.round(start * factor)\n start += item.w\n const w = down ? Math.floor(item.w * factor) : Math.round(start * factor) - x\n end = x + w\n spans.push({ item, x, w, line, factor })\n }\n }\n if (fair(spans, to)) return spans\n }\n return undefined\n}\n\n/**\n * The row kept on one line, items that share a width given the same\n * number of columns: rounded to the nearest when they fit, otherwise\n * rounded down. Items that touched still touch, so the columns left empty\n * gather at the end; items with a gap between them stay near where they\n * were, moved left only as far as it takes to fit.\n */\nfunction oneLine(row: readonly GridItem[], scale: number, to: number): Span[] | undefined {\n const shared = new Map<number, number>()\n for (const item of row) shared.set(item.w, (shared.get(item.w) ?? 0) + 1)\n for (const round of [Math.round, Math.floor]) {\n const spans: Span[] = []\n for (const item of row) {\n const prev = spans[spans.length - 1]\n // items that touched still touch, so empty columns gather at the end\n const x = !prev\n ? Math.round(item.x * scale)\n : prev.item.x + prev.item.w === item.x\n ? prev.x + prev.w\n : Math.max(Math.round(item.x * scale), prev.x + prev.w)\n const w = (shared.get(item.w)! > 1 ? round : Math.round)(item.w * scale)\n spans.push({ item, x, w, line: 0, factor: scale })\n }\n let end = to\n for (let i = spans.length - 1; i >= 0; i--) {\n const span = spans[i]!\n span.x = Math.min(span.x, end - span.w)\n end = span.x\n }\n if (end >= 0 && fair(spans, to)) return spans\n }\n return undefined\n}\n\n/**\n * One row (items sharing a `y`, left to right) on `to` columns, keeping\n * equally wide items equally wide. In order of preference: scaled as is;\n * wrapped onto two lines; kept on one line; wrapped onto more lines. The\n * widths are rounded to the nearest column when that keeps them equal and\n * rounded down otherwise, leaving columns empty. Rows\n * only wrap when the grid gets narrower and the row is a band of its own\n * (all its items equally tall, nothing else reaching into it). Rounded as\n * before when none of that works.\n */\nfunction scaleRow(row: readonly GridItem[], band: boolean, from: number, to: number): Span[] {\n const scale = to / from\n const spans = scaled(row, scale)\n if (fair(spans, to)) return spans\n const wraps = band && to < from\n const two = wraps ? wrapped(row, to, 2) : undefined\n if (two) return two\n const one = oneLine(row, scale, to)\n if (one) return one\n const more = wraps ? wrapped(row, to, row.length) : undefined\n return more ?? spans.map((span) => ({ ...span, w: Math.max(1, span.w) }))\n}\n\n/** A `minW` or `maxW` scaled with the item. */\nconst limit = (value: number | undefined, factor: number) =>\n value === undefined ? undefined : Math.max(1, Math.round(value * factor))\n\n/**\n * The layout worked out for a grid of another width: positions and widths\n * scaled by the ratio of the columns, then settled. Items in a row that\n * were equally wide stay equally wide, by wrapping the row or leaving\n * columns empty (see the docs). On a single column the items are stacked\n * in reading order (top to bottom, then left to right), each keeping its height.\n */\nexport function deriveLayout(\n items: readonly GridItem[],\n from: number,\n options: GridLayoutOptions,\n): readonly GridItem[] {\n const to = options.columns\n if (from === to) return normalizeLayout(items, options)\n if (to === 1) {\n const order = items.map((_, i) => i)\n order.sort((a, b) => items[a]!.y - items[b]!.y || items[a]!.x - items[b]!.x || a - b)\n const out = items.slice()\n let y = 0\n for (const i of order) {\n const item = fitItem({ ...items[i]!, x: 0, w: 1 }, 1)\n out[i] = { ...item, y }\n y += item.h\n }\n return out\n }\n const rows = new Map<number, GridItem[]>()\n for (const item of items) {\n const row = rows.get(item.y)\n if (row) row.push(item)\n else rows.set(item.y, [item])\n }\n const ys = [...rows.keys()]\n ys.sort((a, b) => a - b)\n const placed = new Map<GridItem, GridItem>()\n // lines a row wraps onto push everything below it down\n let shift = 0\n for (const y of ys) {\n const row = rows.get(y)!\n row.sort((a, b) => a.x - b.x)\n const h = row[0]!.h\n const band =\n row.every((item) => item.h === h) &&\n items.every((item) => item.y === y || item.y + item.h <= y || item.y >= y + h)\n const spans = scaleRow(row, band, from, to)\n for (const span of spans)\n placed.set(\n span.item,\n fitItem(\n {\n ...span.item,\n x: span.x,\n y: y + shift + span.line * h,\n w: span.w,\n minW: limit(span.item.minW, span.factor),\n maxW: limit(span.item.maxW, span.factor),\n },\n to,\n ),\n )\n shift += spans[spans.length - 1]!.line * h\n }\n return normalizeLayout(\n items.map((item) => placed.get(item)!),\n options,\n )\n}\n"],"mappings":"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"}
|
package/dist/pivot/pivot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pivot.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } =\n useDashboardWidget<PivotWidgetProps>()\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\nwatch(\n () => props.value.config,\n (next) => (config.value = next),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"pivot.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } =\n useDashboardWidget<PivotWidgetProps>()\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\nwatch(\n () => props.value.config,\n (next) => (config.value = next),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :bordered=\"false\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pivot.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } =\n useDashboardWidget<PivotWidgetProps>()\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\nwatch(\n () => props.value.config,\n (next) => (config.value = next),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":";;;;;;;;;;EAkBA,MAAM,EAAE,OAAO,MAAM,MAAM,WAAW,YAAY,SAAS,UAAU,gBACnE,mBAAqC;EACvC,MAAM,QAAQ,WAAwB;EAEtC,kBAAkB,MAAM,OAAO,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;EACpD,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;EAEhE,MAAM,SAAS,WAAoC,MAAM,MAAM,MAAM;EACrE,YACQ,MAAM,MAAM,SACjB,SAAU,OAAO,QAAQ,IAC5B;EACA,SAAS,SAAS,MAAmB;GACnC,OAAO,QAAQ;GACf,IAAI,QAAQ,OAAO,SAAS,EAAE,QAAQ,KAAK,GAAG,EAAE,OAAO,eAAe,CAAC;EACzE;EACA,MAAM,UAAU,cACd,OAAO,cAAc,WAAW,YAAY,UAAU;;EAGxD,SAAS,OAAO,aAAwC,CAAC,GAAG,SAAkC;GAC5F,MAAM,OAAkB,CAAC;GACzB,KAAK,MAAM,aAAa,YAAY;IAClC,MAAM,QAAQ,QAAQ,OAAO,SAAS;IACtC,IAAI,UAAU,KAAA,GAAW;IACzB,KAAK,KAAK,KAAK;GACjB;GACA,OAAO;EACT;EACA,MAAM,YAAY,eAAe;GAC/B,IAAI,CAAC,MAAM,MAAM,QAAQ,OAAO,KAAA;GAChC,MAAM,UAAU,WAAW;GAC3B,OAAO;IACL,KAAK,OAAO,OAAO,OAAO,MAAM,OAAO;IACvC,QAAQ,OAAO,OAAO,OAAO,SAAS,OAAO;GAC/C;EACF,CAAC;;EAGD,SAAS,MACP,aAAwC,CAAC,GACzC,MACA,QACA;GACA,WAAW,SAAS,WAAW,MAC7B,IAAI,KAAK,SACL,UAAU,OAAO,SAAS,GAAG,cAAc,KAAK,EAAE,GAAG,EAAE,OAAO,OAAO,GAAG,CAAC,IACzE,UAAU,OAAO,SAAS,GAAG,KAAA,CAAS,CAC5C;EACF;;EAGA,SAAS,OAAO,MAAsB;GACpC,IAAI,CAAC,MAAM,MAAM,QAAQ;GACzB,MAAM,EAAE,MAAM,SAAS,SAAS,eAAe,OAAO,SAAS,CAAC;GAChE,MAAM,SAAS,KAAK,KAAK,KAAK,OAAO,GAAG;GACxC,MAAM,YAAY,KAAK,QAAQ,KAAK,OAAO,MAAM;EACnD;;GAIE,OAAAA,UAAA,GAAAC,
|
|
1
|
+
{"version":3,"file":"pivot.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } =\n useDashboardWidget<PivotWidgetProps>()\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\nwatch(\n () => props.value.config,\n (next) => (config.value = next),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :bordered=\"false\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":";;;;;;;;;;EAkBA,MAAM,EAAE,OAAO,MAAM,MAAM,WAAW,YAAY,SAAS,UAAU,gBACnE,mBAAqC;EACvC,MAAM,QAAQ,WAAwB;EAEtC,kBAAkB,MAAM,OAAO,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;EACpD,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;EAEhE,MAAM,SAAS,WAAoC,MAAM,MAAM,MAAM;EACrE,YACQ,MAAM,MAAM,SACjB,SAAU,OAAO,QAAQ,IAC5B;EACA,SAAS,SAAS,MAAmB;GACnC,OAAO,QAAQ;GACf,IAAI,QAAQ,OAAO,SAAS,EAAE,QAAQ,KAAK,GAAG,EAAE,OAAO,eAAe,CAAC;EACzE;EACA,MAAM,UAAU,cACd,OAAO,cAAc,WAAW,YAAY,UAAU;;EAGxD,SAAS,OAAO,aAAwC,CAAC,GAAG,SAAkC;GAC5F,MAAM,OAAkB,CAAC;GACzB,KAAK,MAAM,aAAa,YAAY;IAClC,MAAM,QAAQ,QAAQ,OAAO,SAAS;IACtC,IAAI,UAAU,KAAA,GAAW;IACzB,KAAK,KAAK,KAAK;GACjB;GACA,OAAO;EACT;EACA,MAAM,YAAY,eAAe;GAC/B,IAAI,CAAC,MAAM,MAAM,QAAQ,OAAO,KAAA;GAChC,MAAM,UAAU,WAAW;GAC3B,OAAO;IACL,KAAK,OAAO,OAAO,OAAO,MAAM,OAAO;IACvC,QAAQ,OAAO,OAAO,OAAO,SAAS,OAAO;GAC/C;EACF,CAAC;;EAGD,SAAS,MACP,aAAwC,CAAC,GACzC,MACA,QACA;GACA,WAAW,SAAS,WAAW,MAC7B,IAAI,KAAK,SACL,UAAU,OAAO,SAAS,GAAG,cAAc,KAAK,EAAE,GAAG,EAAE,OAAO,OAAO,GAAG,CAAC,IACzE,UAAU,OAAO,SAAS,GAAG,KAAA,CAAS,CAC5C;EACF;;EAGA,SAAS,OAAO,MAAsB;GACpC,IAAI,CAAC,MAAM,MAAM,QAAQ;GACzB,MAAM,EAAE,MAAM,SAAS,SAAS,eAAe,OAAO,SAAS,CAAC;GAChE,MAAM,SAAS,KAAK,KAAK,KAAK,OAAO,GAAG;GACxC,MAAM,YAAY,KAAK,QAAQ,KAAK,OAAO,MAAM;EACnD;;GAIE,OAAAA,UAAA,GAAAC,YAYEC,MAAA,QAAA,GAAA;IAXI,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,UAAU;IACV,MAAM,KAAA;IACN,QAAQ,QAAA;IACR,QAAQ,OAAA;IACR,WAAW,UAAA;IACZ,MAAK;IACJ,cAAYA,MAAA,IAAA,CAAI,CAAC,OAAO,SAAS,KAAA;IACjC,mBAAe;IACf,aAAY"}
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer dou.components{.dou-grid-layout{--dou-grid-item-radius:var(--dou-radius-container);--dou-grid-col:calc((100cqw - (var(--dou-grid-columns) - 1)*var(--dou-grid-gap-x))/var(--dou-grid-columns));position:relative;box-sizing:border-box;height:calc(var(--dou-grid-rows)*var(--dou-grid-row) + max(var(--dou-grid-rows) - 1,0)*var(--dou-grid-gap-y));container-type:inline-size;width:100%;min-width:0}.dou-grid-layout.is-pointer-dragging{cursor:grabbing}.dou-grid-layout.is-resizing{cursor:nwse-resize}.dou-grid-layout__item,.dou-grid-layout__placeholder{position:absolute;box-sizing:border-box;width:calc(var(--dou-grid-w)*var(--dou-grid-col) + (var(--dou-grid-w) - 1)*var(--dou-grid-gap-x) + var(--dou-grid-dw,0px));height:calc(var(--dou-grid-h)*var(--dou-grid-row) + (var(--dou-grid-h) - 1)*var(--dou-grid-gap-y) + var(--dou-grid-dh,0px));border-radius:var(--dou-grid-item-radius);transform:translate(calc(var(--dou-grid-x)*(var(--dou-grid-col) + var(--dou-grid-gap-x)) + var(--dou-grid-dx,0px)),calc(var(--dou-grid-y)*(var(--dou-grid-row) + var(--dou-grid-gap-y)) + var(--dou-grid-dy,0px)));top:0;left:0}.dou-grid-layout__item{display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);outline:none;min-width:0}.dou-grid-layout__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-grid-layout.is-editable .dou-grid-layout__item.is-movable{user-select:none;-webkit-touch-callout:none}.dou-grid-layout.is-editable:not(:-webkit-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:-moz-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:is(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-arranging .dou-grid-layout__item{transition:transform var(--dou-motion-duration-normal)var(--dou-motion-easing)}.dou-grid-layout__item.is-dragging,.dou-grid-layout__item.is-resizing{z-index:2;box-shadow:var(--dou-shadow-lg)}.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-dragging,.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-resizing{transition:none}.dou-grid-layout__placeholder{z-index:1;border:1px dashed var(--dou-color-border-strong);background-color:color-mix(in oklab,var(--dou-color-text)4%,transparent);pointer-events:none}.dou-grid-layout.is-arranging .dou-grid-layout__placeholder{transition:transform var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-grid-layout__resize{position:absolute;z-index:1;touch-action:none}.dou-grid-layout__resize.is-e{cursor:ew-resize;width:8px;top:8px;bottom:16px;right:-4px}.dou-grid-layout__resize.is-s{cursor:ns-resize;height:8px;bottom:-4px;left:8px;right:16px}.dou-grid-layout__resize.is-se{cursor:nwse-resize;opacity:0;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing);width:20px;height:20px;bottom:0;right:0}.dou-grid-layout__resize.is-se:after{position:absolute;box-sizing:border-box;border-right:2px solid var(--dou-color-text-tertiary);border-bottom:2px solid var(--dou-color-text-tertiary);content:"";border-bottom-right-radius:4px;width:8px;height:8px;bottom:5px;right:5px}.dou-grid-layout__item:hover>.dou-grid-layout__resize.is-se,.dou-grid-layout__item.is-resizing>.dou-grid-layout__resize.is-se{opacity:1}.dou-grid-layout__item:focus-visible>.dou-grid-layout__resize.is-se{opacity:1}@media (pointer:coarse){.dou-grid-layout__resize.is-se{opacity:1;width:32px;height:32px}}.dou-grid-layout__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}}@layer dou.components{.dou-dashboard{position:relative;outline:none;min-width:0}.dou-dashboard__widget{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:inherit;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);overflow:hidden;flex-direction:column;min-width:0;min-height:0}.dou-grid-layout__item.is-dragging>.dou-dashboard__widget,.dou-grid-layout__item.is-resizing>.dou-dashboard__widget{border-color:var(--dou-color-border-strong)}.dou-dashboard__widget.has-peers{outline:1.5px solid var(--dou-dashboard-peer-color);outline-offset:2px}.dou-dashboard__peers{position:absolute;z-index:1;display:flex;overflow:hidden;pointer-events:none;gap:4px;max-width:calc(100% - 24px);margin-bottom:-10px;bottom:100%;left:12px}.dou-dashboard__peer{background-color:var(--dou-dashboard-peer-color);color:oklch(from var(--dou-dashboard-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;flex:none;padding:0 6px;line-height:18px}.dou-dashboard__peer.is-focus{animation:dou-dashboard-peer-name var(--dou-motion-duration-fast)var(--dou-motion-easing)3s forwards}.dou-dashboard__header{display:flex;flex:none;align-items: center;gap:8px;height:40px;padding:0 8px 0 16px}.dou-dashboard__title{overflow:hidden;color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:min(6em,40%)}.dou-dashboard__title .dou-editable__view{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:inherit}.dou-dashboard__links{display:flex;overflow:hidden;flex:0 auto;gap:4px;min-width:0;max-width:60%}.dou-dashboard__links .dou-tag{min-width:0;max-width:100%}.dou-dashboard__links .dou-tag__label{overflow-x:clip;white-space:nowrap;text-overflow:ellipsis;min-width:0}.dou-dashboard__actions{display:flex;color:var(--dou-color-text-tertiary);flex:none;align-items: center;gap:2px}.dou-dashboard__trigger{display:inline-flex;flex:none}.dou-dashboard__export-error{flex:none;padding:0 8px 8px}.dou-dashboard__export-error .dou-alert__description{overflow-y:auto;max-height:4.5lh}.dou-dashboard__body{position:relative;flex:auto;min-width:0;min-height:0;padding:0 16px 16px}.dou-dashboard__body.is-fullscreen{height:100%;padding:0}.dou-dashboard__content{min-width:0;height:100%}.dou-dashboard__notice{display:grid;color:var(--dou-color-text-tertiary);text-align:center;place-items: center;height:100%}.dou-dashboard__status{position:absolute;display:flex;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:8px;padding:0 16px 16px;inset:0}.dou-dashboard__status.is-loading{background-color:color-mix(in oklab,var(--dou-color-bg-surface)72%,transparent);animation:dou-dashboard-fade-in var(--dou-motion-duration-fast)var(--dou-motion-easing).12s both}.dou-dashboard__status-icon{color:var(--dou-color-danger);width:20px;height:20px}.dou-dashboard__empty{position:absolute;display:grid;border:1px dashed var(--dou-color-border);border-radius:var(--dou-radius-container);pointer-events:none;place-items: center;inset:0}.dou-dashboard__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-dashboard__settings{display:flex;flex-direction:column;gap:16px}.dou-dashboard__field{display:flex;flex-direction:column;gap:8px}.dou-dashboard__field-hint{color:var(--dou-color-text-tertiary);font-size:var(--dou-font-size-sm)}.dou-dashboard__field-row{display:flex;flex-wrap:wrap;gap:16px}.dou-dashboard__field-row>.dou-dashboard__field{flex:120px;min-width:0}.dou-dashboard__columns{display:flex;flex-direction:column;gap:8px}.dou-dashboard__column{display:grid;grid-template-columns:minmax(0,1fr)minmax(0,1fr);align-items: center;gap:8px}.dou-dashboard__field-label{color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium)}@keyframes dou-dashboard-fade-in{0%{opacity:0}}.dou-dashboard-palette{display:flex;list-style:none;flex-direction:column;gap:8px;margin:0;padding:0}.dou-dashboard-palette.is-horizontal{flex-flow:wrap}.dou-dashboard-palette>li{margin:0}.dou-dashboard-palette__item{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:var(--dou-font-size-sm);cursor:grab;user-select:none;-webkit-touch-callout:none;transition:border-color var(--dou-motion-duration-fast)var(--dou-motion-easing);align-items: center;gap:8px;width:100%;height:32px;padding:0 12px}.dou-dashboard-palette__item:hover:not(:disabled){border-color:var(--dou-color-border-strong)}.dou-dashboard-palette__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-dashboard-palette__item:disabled{color:var(--dou-color-text-tertiary);cursor:not-allowed}.dou-dashboard-palette__icon{color:var(--dou-color-text-secondary);flex:none;width:16px;height:16px}.dou-dashboard-palette__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dou-dashboard-filter{display:flex;flex-wrap:wrap;align-items: center;gap:8px 16px}.dou-dashboard-filter__field{display:flex;align-items: center;gap:8px;min-width:0}.dou-dashboard-filter__label{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;flex:none}.dou-dashboard-filter__control{width:144px;min-width:0}.dou-dashboard-filter__control.is-range{width:272px}.dou-dashboard-filter__extra{display:flex;align-items: center;gap:4px;margin-left:auto}@media (max-width:480px){.dou-dashboard-filter__field{flex:100%}.dou-dashboard-filter__label{width:4em}.dou-dashboard-filter__control,.dou-dashboard-filter__control.is-range{flex:auto;width:auto}}.dou-dashboard-stat{display:flex;container-type:inline-size;flex-direction:column;justify-content:space-between;gap:8px;height:100%}@container (width<=200px){.dou-dashboard-stat .dou-statistic{--dou-statistic-value-size:22px}}.dou-dashboard-stat__spark{flex:none;margin:0 -16px -16px}.dou-dashboard-text{overflow:auto;color:var(--dou-color-text);white-space:pre-wrap;overflow-wrap:anywhere;height:100%;line-height:1.6}.dou-dashboard-text.is-sm{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-dashboard-text.is-md{font-size:var(--dou-font-size-md)}.dou-dashboard-text.is-lg{font-size:var(--dou-font-size-lg);font-weight:var(--dou-font-weight-medium);line-height:1.4}.dou-dashboard.is-exporting .dou-dashboard__actions{display:none}.dou-dashboard.is-exporting .dou-dashboard__links .dou-tag__close{display:none}.dou-dashboard.is-exporting .dou-dashboard__export-error{display:none}.dou-dashboard.is-exporting .dou-dashboard__peers{display:none}.dou-dashboard.is-exporting .dou-grid-layout__resize{display:none}.dou-dashboard.is-exporting .dou-dashboard__live{display:none}.dou-dashboard.is-exporting .dou-grid-layout__item{outline:none}.dou-dashboard.is-exporting .dou-dashboard__widget{outline:none}@media print{.dou-dashboard{print-color-adjust:exact}.dou-dashboard__actions,.dou-dashboard__links .dou-tag__close,.dou-dashboard__export-error,.dou-dashboard__peers,.dou-grid-layout__resize,.dou-dashboard-filter__clear,.dou-dashboard-filter__extra{display:none}.dou-grid-layout__item{outline:none;break-inside:avoid}.dou-dashboard__widget{outline:none}}}@keyframes dou-dashboard-peer-name{to{opacity:0;visibility:hidden}}
|
|
1
|
+
@layer dou.components{.dou-grid-layout{--dou-grid-item-radius:var(--dou-radius-container);--dou-grid-col:calc((100cqw - (var(--dou-grid-columns) - 1)*var(--dou-grid-gap-x))/var(--dou-grid-columns));position:relative;box-sizing:border-box;height:calc(var(--dou-grid-rows)*var(--dou-grid-row) + max(var(--dou-grid-rows) - 1,0)*var(--dou-grid-gap-y));container-type:inline-size;width:100%;min-width:0}.dou-grid-layout.is-pointer-dragging{cursor:grabbing}.dou-grid-layout.is-resizing{cursor:nwse-resize}.dou-grid-layout__item,.dou-grid-layout__placeholder{position:absolute;box-sizing:border-box;width:calc(var(--dou-grid-w)*var(--dou-grid-col) + (var(--dou-grid-w) - 1)*var(--dou-grid-gap-x) + var(--dou-grid-dw,0px));height:calc(var(--dou-grid-h)*var(--dou-grid-row) + (var(--dou-grid-h) - 1)*var(--dou-grid-gap-y) + var(--dou-grid-dh,0px));border-radius:var(--dou-grid-item-radius);transform:translate(calc(var(--dou-grid-x)*(var(--dou-grid-col) + var(--dou-grid-gap-x)) + var(--dou-grid-dx,0px)),calc(var(--dou-grid-y)*(var(--dou-grid-row) + var(--dou-grid-gap-y)) + var(--dou-grid-dy,0px)));top:0;left:0}.dou-grid-layout__item{display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);outline:none;min-width:0}.dou-grid-layout__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-grid-layout.is-editable .dou-grid-layout__item.is-movable{user-select:none;-webkit-touch-callout:none}.dou-grid-layout.is-editable:not(:-webkit-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:-moz-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:is(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-arranging .dou-grid-layout__item{transition:transform var(--dou-motion-duration-normal)var(--dou-motion-easing)}.dou-grid-layout__item.is-dragging,.dou-grid-layout__item.is-resizing{z-index:2;box-shadow:var(--dou-shadow-lg)}.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-dragging,.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-resizing{transition:none}.dou-grid-layout__placeholder{z-index:1;border:1px dashed var(--dou-color-border-strong);background-color:color-mix(in oklab,var(--dou-color-text)4%,transparent);pointer-events:none}.dou-grid-layout.is-arranging .dou-grid-layout__placeholder{transition:transform var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-grid-layout__resize{position:absolute;z-index:1;touch-action:none}.dou-grid-layout__resize.is-e{cursor:ew-resize;width:8px;top:8px;bottom:16px;right:-4px}.dou-grid-layout__resize.is-s{cursor:ns-resize;height:8px;bottom:-4px;left:8px;right:16px}.dou-grid-layout__resize.is-se{cursor:nwse-resize;opacity:0;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing);width:20px;height:20px;bottom:0;right:0}.dou-grid-layout__resize.is-se:after{position:absolute;box-sizing:border-box;border-right:2px solid var(--dou-color-text-tertiary);border-bottom:2px solid var(--dou-color-text-tertiary);content:"";border-bottom-right-radius:4px;width:8px;height:8px;bottom:5px;right:5px}.dou-grid-layout__item:hover>.dou-grid-layout__resize.is-se,.dou-grid-layout__item.is-resizing>.dou-grid-layout__resize.is-se{opacity:1}.dou-grid-layout__item:focus-visible>.dou-grid-layout__resize.is-se{opacity:1}@media (pointer:coarse){.dou-grid-layout__resize.is-se{opacity:1;width:32px;height:32px}}.dou-grid-layout__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}}@layer dou.components{.dou-dashboard{position:relative;outline:none;min-width:0}.dou-dashboard__widget{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:inherit;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);overflow:hidden;flex-direction:column;min-width:0;min-height:0}.dou-grid-layout__item.is-dragging>.dou-dashboard__widget,.dou-grid-layout__item.is-resizing>.dou-dashboard__widget{border-color:var(--dou-color-border-strong)}.dou-dashboard__widget.has-peers{outline:1.5px solid var(--dou-dashboard-peer-color);outline-offset:2px}.dou-dashboard__peers{position:absolute;z-index:1;display:flex;overflow:hidden;pointer-events:none;gap:4px;max-width:calc(100% - 24px);margin-bottom:-10px;bottom:100%;left:12px}.dou-dashboard__peer{background-color:var(--dou-dashboard-peer-color);color:oklch(from var(--dou-dashboard-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;flex:none;padding:0 6px;line-height:18px}.dou-dashboard__peer.is-focus{animation:dou-dashboard-peer-name var(--dou-motion-duration-fast)var(--dou-motion-easing)3s forwards}.dou-dashboard__header{display:flex;flex:none;align-items: center;gap:8px;height:40px;padding:0 8px 0 16px}.dou-dashboard__title{overflow:hidden;color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:min(6em,40%)}.dou-dashboard__title .dou-editable__view{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:inherit}.dou-dashboard__links{display:flex;overflow:hidden;flex:0 auto;gap:4px;min-width:0;max-width:60%}.dou-dashboard__links .dou-tag{min-width:0;max-width:100%}.dou-dashboard__links .dou-tag__label{overflow-x:clip;white-space:nowrap;text-overflow:ellipsis;min-width:0}.dou-dashboard__actions{display:flex;color:var(--dou-color-text-tertiary);flex:none;align-items: center;gap:2px}.dou-dashboard__export-error{flex:none;padding:0 8px 8px}.dou-dashboard__export-error .dou-alert__description{overflow-y:auto;max-height:4.5lh}.dou-dashboard__body{position:relative;flex:auto;min-width:0;min-height:0;padding:0 16px 16px}.dou-dashboard__body.is-fullscreen{height:100%;padding:0}.dou-dashboard__content{min-width:0;height:100%}.dou-dashboard__notice{display:grid;color:var(--dou-color-text-tertiary);text-align:center;place-items: center;height:100%}.dou-dashboard__status{position:absolute;display:flex;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:8px;padding:0 16px 16px;inset:0}.dou-dashboard__status.is-loading{background-color:color-mix(in oklab,var(--dou-color-bg-surface)72%,transparent);animation:dou-dashboard-fade-in var(--dou-motion-duration-fast)var(--dou-motion-easing).12s both}.dou-dashboard__status-icon{color:var(--dou-color-danger);width:20px;height:20px}.dou-dashboard__empty{position:absolute;display:grid;border:1px dashed var(--dou-color-border);border-radius:var(--dou-radius-container);pointer-events:none;place-items: center;inset:0}.dou-dashboard__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-dashboard__settings{display:flex;flex-direction:column;gap:16px}.dou-dashboard__field{display:flex;flex-direction:column;gap:8px}.dou-dashboard__field-hint{color:var(--dou-color-text-tertiary);font-size:var(--dou-font-size-sm)}.dou-dashboard__field-row{display:flex;flex-wrap:wrap;gap:16px}.dou-dashboard__field-row>.dou-dashboard__field{flex:120px;min-width:0}.dou-dashboard__columns{display:flex;flex-direction:column;gap:8px}.dou-dashboard__column{display:grid;grid-template-columns:minmax(0,1fr)minmax(0,1fr);align-items: center;gap:8px}.dou-dashboard__field-label{color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium)}@keyframes dou-dashboard-fade-in{0%{opacity:0}}.dou-dashboard-palette{display:flex;list-style:none;flex-direction:column;gap:8px;margin:0;padding:0}.dou-dashboard-palette.is-horizontal{flex-flow:wrap}.dou-dashboard-palette>li{margin:0}.dou-dashboard-palette__item{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:var(--dou-font-size-sm);cursor:grab;user-select:none;-webkit-touch-callout:none;transition:border-color var(--dou-motion-duration-fast)var(--dou-motion-easing);align-items: center;gap:8px;width:100%;height:32px;padding:0 12px}.dou-dashboard-palette__item:hover:not(:disabled){border-color:var(--dou-color-border-strong)}.dou-dashboard-palette__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-dashboard-palette__item:disabled{color:var(--dou-color-text-tertiary);cursor:not-allowed}.dou-dashboard-palette__icon{color:var(--dou-color-text-secondary);flex:none;width:16px;height:16px}.dou-dashboard-palette__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dou-dashboard-filter{display:flex;flex-wrap:wrap;align-items: center;gap:8px 16px}.dou-dashboard-filter__field{display:flex;align-items: center;gap:8px;min-width:0}.dou-dashboard-filter__label{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;flex:none}.dou-dashboard-filter__control{width:144px;min-width:0}.dou-dashboard-filter__control.is-range{width:272px}.dou-dashboard-filter__extra{display:flex;align-items: center;gap:4px;margin-left:auto}@media (max-width:480px){.dou-dashboard-filter__field{flex:100%}.dou-dashboard-filter__label{width:4em}.dou-dashboard-filter__control,.dou-dashboard-filter__control.is-range{flex:auto;width:auto}}.dou-dashboard-stat{display:flex;container-type:inline-size;flex-direction:column;justify-content:space-between;gap:8px;height:100%}@container (width<=200px){.dou-dashboard-stat .dou-statistic{--dou-statistic-value-size:22px}}.dou-dashboard-stat__spark{flex:none;margin:0 -16px -16px}.dou-dashboard-text{overflow:auto;color:var(--dou-color-text);white-space:pre-wrap;overflow-wrap:anywhere;height:100%;line-height:1.6}.dou-dashboard-text.is-sm{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-dashboard-text.is-md{font-size:var(--dou-font-size-md)}.dou-dashboard-text.is-lg{font-size:var(--dou-font-size-lg);font-weight:var(--dou-font-weight-medium);line-height:1.4}.dou-dashboard.is-exporting .dou-dashboard__actions{display:none}.dou-dashboard.is-exporting .dou-dashboard__links .dou-tag__close{display:none}.dou-dashboard.is-exporting .dou-dashboard__export-error{display:none}.dou-dashboard.is-exporting .dou-dashboard__peers{display:none}.dou-dashboard.is-exporting .dou-grid-layout__resize{display:none}.dou-dashboard.is-exporting .dou-dashboard__live{display:none}.dou-dashboard.is-exporting .dou-grid-layout__item{outline:none}.dou-dashboard.is-exporting .dou-dashboard__widget{outline:none}@media print{.dou-dashboard{print-color-adjust:exact}.dou-dashboard__actions,.dou-dashboard__links .dou-tag__close,.dou-dashboard__export-error,.dou-dashboard__peers,.dou-grid-layout__resize,.dou-dashboard-filter__clear,.dou-dashboard-filter__extra{display:none}.dou-grid-layout__item{outline:none;break-inside:avoid}.dou-dashboard__widget{outline:none}}}@keyframes dou-dashboard-peer-name{to{opacity:0;visibility:hidden}}
|
package/dist/style.js
CHANGED
|
@@ -4,9 +4,15 @@ import 'dou-ui/components/dialog/style'
|
|
|
4
4
|
import 'dou-ui/components/drawer/style'
|
|
5
5
|
import 'dou-ui/components/editable/style'
|
|
6
6
|
import 'dou-ui/components/dropdown/style'
|
|
7
|
-
import 'dou-ui/components/empty/style'
|
|
8
7
|
import 'dou-ui/components/grid/style'
|
|
8
|
+
import 'dou-ui/components/input-number/style'
|
|
9
|
+
import 'dou-ui/components/segmented-control/style'
|
|
9
10
|
import 'dou-ui/components/select/style'
|
|
11
|
+
import 'dou-ui/components/sparkline/style'
|
|
12
|
+
import 'dou-ui/components/statistic/style'
|
|
13
|
+
import 'dou-ui/components/switch/style'
|
|
14
|
+
import 'dou-ui/components/table/style'
|
|
15
|
+
import 'dou-ui/components/textarea/style'
|
|
10
16
|
import 'dou-ui/components/tooltip/style'
|
|
11
17
|
import '@dou-ui/sheet/style'
|
|
12
18
|
import './style.css'
|
|
@@ -42,9 +42,10 @@ export declare function resizeItemBy(items: readonly GridItem[], id: string, dw:
|
|
|
42
42
|
export declare function findPlace(items: readonly GridItem[], size: GridSize, options: GridLayoutOptions): GridPosition;
|
|
43
43
|
/**
|
|
44
44
|
* The layout worked out for a grid of another width: positions and widths
|
|
45
|
-
* scaled by the ratio of the columns, then settled.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* scaled by the ratio of the columns, then settled. Items in a row that
|
|
46
|
+
* were equally wide stay equally wide, by wrapping the row or leaving
|
|
47
|
+
* columns empty (see the docs). On a single column the items are stacked
|
|
48
|
+
* in reading order (top to bottom, then left to right), each keeping its height.
|
|
48
49
|
*/
|
|
49
50
|
export declare function deriveLayout(items: readonly GridItem[], from: number, options: GridLayoutOptions): readonly GridItem[];
|
|
50
51
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","names":["_sfc_main"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props, data, size, setWorkbook } = useDashboardWidget<TableWidgetProps>()\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"table.js","names":["_sfc_main"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props, data, size, setWorkbook } = useDashboardWidget<TableWidgetProps>()\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :bordered=\"false\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props, data, size, setWorkbook } = useDashboardWidget<TableWidgetProps>()\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":";;;;;;;;;EAUA,MAAM,EAAE,OAAO,MAAM,MAAM,gBAAgB,mBAAqC;EAChF,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;;EAEhE,MAAM,OAAO,eAAe;GAC1B,MAAM,sBAAM,IAAI,QAAiC;GACjD,MAAM,QAAQ,MAAM,MAAM;GAC1B,KAAK,MAAM,SAAS,KAAK,UAAU,IAAI,IAAI,KAAK,QAAS,IAAI,SAA6B,KAAK,CAAC;GAChG,OAAO;EACT,CAAC;EACD,MAAM,UAAU,QAAiC,KAAK,MAAM,IAAI,GAAG,KAAK;EACxE,MAAM,SAAS,IAAI,KAAK,aAAa;;EAErC,MAAM,OAAO,IAAsB;EACnC,MAAM,OAAO,IAAI,EAAE;EACnB,gBAAgB;GACd,MAAM,OAAO,KAAK,OAAO,IAAI,cAAc,QAAQ;GACnD,IAAI,MAAM,KAAK,QAAQ,iBAAiB,IAAI,CAAC,CAAC;EAChD,CAAC;EACD,IAAI;;EAEJ,SAAS,UAAU,MAAc;GAC/B,YACE,OAAO,aAAa,cAAc,OAAO,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI;GAC3F,IAAI,WAAW,KAAK,OAAO;IACzB,QAAQ,OAAO,KAAK;IACpB,OAAO,QAAQ,YAAY,IAAI,CAAC,CAAC;GACnC;GACA,IAAI,QAAQ;GACZ,KAAK,MAAM,QAAQ,MAAM,SAAS,KAAK,WAAW,CAAC,IAAI,QAAS,KAAK;GACrE,OAAO;EACT;;EAEA,SAAS,WAAW,OAAe,OAAkB;GACnD,IAAI,SAAS,UAAU,KAAK;GAC5B,KAAK,MAAM,QAAQ,OAAO,SAAS,KAAK,IAAI,QAAQ,UAAU,OAAO,QAAQ,EAAE,CAAC,CAAC;GACjF,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,EAAE;EAC7C;EACA,MAAM,UAAU,eAA8B;GAC5C,MAAM,QAAQ,KAAK,MAAM;GAGzB,QADE,MAAM,MAAM,WAAW,SAAS,KAAK,KAAK,CAAC,CAAC,KAAK,SAAS,EAAE,IAAI,EAAE,EAAA,CACxD,KAAK,EAAE,KAAK,YAAY;IAClC,MAAM,UAAU,OAAO,QAAQ,SAAS;IAExC,MAAM,QAAQ,WACT,QACC,OAAO,IAAI,SAAS,WAAW,OAAO,OAAO,IAAI,IAAc,IAAI,IAAI,OACzE,KAAA;IACJ,MAAM,SAAS,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,QAAS,QAAQ,MAAM,GAAG,IAAI,IAAI,IAAK;IACnF,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM;IAC7C,OAAO;KACL;KACA,OAAO,SAAS;KAChB,OAAO,UAAU,QAAQ,KAAA;KACzB,UAAU;KAEV,OAAO;KACP,UAAU;KACV;IACF;GACF,CAAC;EACH,CAAC;EAED,kBACE,eACE,IACA,QAAQ,MAAM,KAAK,YAAY;GAC7B,KAAK,OAAO;GACZ,OAAO,OAAO,OAAO,KAAK;GAC1B,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;EAC3D,EAAE,GACF,KAAK,KACP,CACF;;GAIE,OAAAA,UAAA,GAAAC,
|
|
1
|
+
{"version":3,"file":"table.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props, data, size, setWorkbook } = useDashboardWidget<TableWidgetProps>()\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :bordered=\"false\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":";;;;;;;;;EAUA,MAAM,EAAE,OAAO,MAAM,MAAM,gBAAgB,mBAAqC;EAChF,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;;EAEhE,MAAM,OAAO,eAAe;GAC1B,MAAM,sBAAM,IAAI,QAAiC;GACjD,MAAM,QAAQ,MAAM,MAAM;GAC1B,KAAK,MAAM,SAAS,KAAK,UAAU,IAAI,IAAI,KAAK,QAAS,IAAI,SAA6B,KAAK,CAAC;GAChG,OAAO;EACT,CAAC;EACD,MAAM,UAAU,QAAiC,KAAK,MAAM,IAAI,GAAG,KAAK;EACxE,MAAM,SAAS,IAAI,KAAK,aAAa;;EAErC,MAAM,OAAO,IAAsB;EACnC,MAAM,OAAO,IAAI,EAAE;EACnB,gBAAgB;GACd,MAAM,OAAO,KAAK,OAAO,IAAI,cAAc,QAAQ;GACnD,IAAI,MAAM,KAAK,QAAQ,iBAAiB,IAAI,CAAC,CAAC;EAChD,CAAC;EACD,IAAI;;EAEJ,SAAS,UAAU,MAAc;GAC/B,YACE,OAAO,aAAa,cAAc,OAAO,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI;GAC3F,IAAI,WAAW,KAAK,OAAO;IACzB,QAAQ,OAAO,KAAK;IACpB,OAAO,QAAQ,YAAY,IAAI,CAAC,CAAC;GACnC;GACA,IAAI,QAAQ;GACZ,KAAK,MAAM,QAAQ,MAAM,SAAS,KAAK,WAAW,CAAC,IAAI,QAAS,KAAK;GACrE,OAAO;EACT;;EAEA,SAAS,WAAW,OAAe,OAAkB;GACnD,IAAI,SAAS,UAAU,KAAK;GAC5B,KAAK,MAAM,QAAQ,OAAO,SAAS,KAAK,IAAI,QAAQ,UAAU,OAAO,QAAQ,EAAE,CAAC,CAAC;GACjF,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,EAAE;EAC7C;EACA,MAAM,UAAU,eAA8B;GAC5C,MAAM,QAAQ,KAAK,MAAM;GAGzB,QADE,MAAM,MAAM,WAAW,SAAS,KAAK,KAAK,CAAC,CAAC,KAAK,SAAS,EAAE,IAAI,EAAE,EAAA,CACxD,KAAK,EAAE,KAAK,YAAY;IAClC,MAAM,UAAU,OAAO,QAAQ,SAAS;IAExC,MAAM,QAAQ,WACT,QACC,OAAO,IAAI,SAAS,WAAW,OAAO,OAAO,IAAI,IAAc,IAAI,IAAI,OACzE,KAAA;IACJ,MAAM,SAAS,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,QAAS,QAAQ,MAAM,GAAG,IAAI,IAAI,IAAK;IACnF,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM;IAC7C,OAAO;KACL;KACA,OAAO,SAAS;KAChB,OAAO,UAAU,QAAQ,KAAA;KACzB,UAAU;KAEV,OAAO;KACP,UAAU;KACV;IACF;GACF,CAAC;EACH,CAAC;EAED,kBACE,eACE,IACA,QAAQ,MAAM,KAAK,YAAY;GAC7B,KAAK,OAAO;GACZ,OAAO,OAAO,OAAO,KAAK;GAC1B,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;EAC3D,EAAE,GACF,KAAK,KACP,CACF;;GAIE,OAAAA,UAAA,GAAAC,YAUEC,MAAA,QAAA,GAAA;IATI,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,UAAU;IACV,MAAM,KAAA;IACN,SAAS,QAAA;IACT,WAAS;IACV,MAAK;IACJ,cAAYA,MAAA,IAAA,CAAI,CAAC,OAAO,SAAS,KAAA;IACjC,SAAS,KAAA,MAAK,SAAM"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dou-ui/dashboard",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"description": "DouUI 的仪表盘:可拖动、可缩放的网格布局与仪表盘设计器",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vue",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"build": "vite build && vue-tsc -p tsconfig.build.json && bun scripts/build-style.ts"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@dou-ui/chart": "0.1.0-alpha.
|
|
71
|
-
"@dou-ui/pivot": "0.1.0-alpha.
|
|
72
|
-
"dou-ui": "0.1.0-alpha.
|
|
70
|
+
"@dou-ui/chart": "0.1.0-alpha.3",
|
|
71
|
+
"@dou-ui/pivot": "0.1.0-alpha.3",
|
|
72
|
+
"dou-ui": "0.1.0-alpha.3",
|
|
73
73
|
"vue": "^3.5.0",
|
|
74
74
|
"yjs": "^13.6.0"
|
|
75
75
|
},
|
|
@@ -85,12 +85,12 @@
|
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@dou-ui/icons": "0.1.0-alpha.
|
|
89
|
-
"@dou-ui/sheet": "0.1.0-alpha.
|
|
88
|
+
"@dou-ui/icons": "0.1.0-alpha.3",
|
|
89
|
+
"@dou-ui/sheet": "0.1.0-alpha.3"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@dou-ui/chart": "0.1.0-alpha.
|
|
93
|
-
"@dou-ui/pivot": "0.1.0-alpha.
|
|
92
|
+
"@dou-ui/chart": "0.1.0-alpha.3",
|
|
93
|
+
"@dou-ui/pivot": "0.1.0-alpha.3",
|
|
94
94
|
"y-protocols": "^1.0.7",
|
|
95
95
|
"yjs": "^13.6.33"
|
|
96
96
|
},
|