@dou-ui/dashboard 0.1.0-alpha.2 → 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/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/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/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}}
|
|
@@ -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
|
},
|