@dou-ui/dashboard 0.1.0-alpha.4 → 0.1.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/chart/chart-settings.js.map +1 -1
  2. package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js +10 -8
  3. package/dist/chart/chart-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  4. package/dist/chart/chart.js.map +1 -1
  5. package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js +19 -15
  6. package/dist/chart/chart.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/chart/read-props.js +26 -0
  8. package/dist/chart/read-props.js.map +1 -0
  9. package/dist/dashboard/dashboard.js.map +1 -1
  10. package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js +27 -4
  11. package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  12. package/dist/dashboard/error-boundary.js +64 -0
  13. package/dist/dashboard/error-boundary.js.map +1 -0
  14. package/dist/dashboard/frame-context.js.map +1 -1
  15. package/dist/dashboard/widget-body.js.map +1 -1
  16. package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js +53 -12
  17. package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js.map +1 -1
  18. package/dist/dashboard/widget-frame.js.map +1 -1
  19. package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +4 -2
  20. package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -1
  21. package/dist/dashboard/widget-settings.js.map +1 -1
  22. package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js +31 -5
  23. package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/locale.js +6 -0
  26. package/dist/locale.js.map +1 -1
  27. package/dist/pivot/pivot-settings.js.map +1 -1
  28. package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js +6 -4
  29. package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/pivot/pivot.js.map +1 -1
  31. package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js +4 -2
  32. package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/pivot/read-props.js +44 -0
  34. package/dist/pivot/read-props.js.map +1 -0
  35. package/dist/style.css +1 -1
  36. package/dist/types/chart/read-props.d.ts +3 -0
  37. package/dist/types/dashboard/dashboard.vue.d.ts +2 -0
  38. package/dist/types/dashboard/error-boundary.d.ts +12 -0
  39. package/dist/types/dashboard/frame-context.d.ts +2 -0
  40. package/dist/types/dashboard/types.d.ts +17 -0
  41. package/dist/types/dashboard/widget-body.vue.d.ts +2 -0
  42. package/dist/types/dashboard/widget-settings.vue.d.ts +4 -0
  43. package/dist/types/index.d.ts +3 -1
  44. package/dist/types/locale.d.ts +4 -0
  45. package/dist/types/pivot/read-props.d.ts +3 -0
  46. package/dist/types/widgets/index.d.ts +1 -1
  47. package/dist/types/widgets/read-props.d.ts +4 -0
  48. package/dist/types/widgets/shared.d.ts +20 -4
  49. package/dist/widgets/index.js +2 -2
  50. package/dist/widgets/index.js.map +1 -1
  51. package/dist/widgets/read-props.js +52 -0
  52. package/dist/widgets/read-props.js.map +1 -0
  53. package/dist/widgets/shared.js +27 -5
  54. package/dist/widgets/shared.js.map +1 -1
  55. package/dist/widgets/stat-settings.js.map +1 -1
  56. package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js +12 -10
  57. package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  58. package/dist/widgets/stat.js.map +1 -1
  59. package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js +10 -13
  60. package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js.map +1 -1
  61. package/dist/widgets/table-settings.js.map +1 -1
  62. package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js +6 -4
  63. package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  64. package/dist/widgets/table.js.map +1 -1
  65. package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js +3 -1
  66. package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/widgets/text-settings.js.map +1 -1
  68. package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js +5 -3
  69. package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  70. package/dist/widgets/text.js.map +1 -1
  71. package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js +5 -3
  72. package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js.map +1 -1
  73. package/package.json +8 -8
@@ -1,27 +1,33 @@
1
1
  import { format } from "../locale.js";
2
2
  import { observersKey } from "./observers.js";
3
+ import { useErrorBoundary } from "./error-boundary.js";
3
4
  import { provideWidgetContext } from "../widget/context.js";
4
5
  import { DouButton, DouEmpty, DouSpinner } from "dou-ui";
5
- import { createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, onBeforeUnmount, onMounted, openBlock, ref, resolveDynamicComponent, toDisplayString, unref, withCtx } from "vue";
6
+ import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, nextTick, onBeforeUnmount, onMounted, openBlock, ref, resolveDynamicComponent, toDisplayString, unref, watch, withCtx } from "vue";
6
7
  import { AlertCircleIcon } from "@dou-ui/icons";
7
8
  // src/dashboard/widget-body.vue?vue&type=script&setup=true&lang.ts
8
9
  var _hoisted_1 = ["aria-busy"];
9
10
  var _hoisted_2 = {
10
- key: 1,
11
+ key: 2,
11
12
  class: "dou-dashboard__notice"
12
13
  };
13
14
  var _hoisted_3 = {
14
15
  key: 0,
15
- class: "dou-dashboard__status is-loading",
16
- role: "status"
16
+ class: "dou-dashboard__status is-error",
17
+ role: "alert"
17
18
  };
18
19
  var _hoisted_4 = {
19
20
  key: 1,
20
- class: "dou-dashboard__status is-error",
21
- role: "alert"
21
+ class: "dou-dashboard__status is-loading",
22
+ role: "status"
22
23
  };
23
24
  var _hoisted_5 = {
24
25
  key: 2,
26
+ class: "dou-dashboard__status is-error",
27
+ role: "alert"
28
+ };
29
+ var _hoisted_6 = {
30
+ key: 3,
25
31
  class: "dou-dashboard__status is-empty"
26
32
  };
27
33
  var widget_body_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -34,7 +40,8 @@ var widget_body_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
34
40
  fullscreen: { type: Boolean },
35
41
  messages: {},
36
42
  setProps: { type: Function },
37
- setWorkbook: { type: Function }
43
+ setWorkbook: { type: Function },
44
+ reportError: { type: Function }
38
45
  },
39
46
  setup(__props) {
40
47
  const props = __props;
@@ -50,7 +57,7 @@ var widget_body_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
50
57
  });
51
58
  });
52
59
  onBeforeUnmount(() => stop?.());
53
- const { status } = provideWidgetContext({
60
+ const { status, data } = provideWidgetContext({
54
61
  widget: () => props.widget,
55
62
  editing: () => props.editing,
56
63
  fullscreen: () => !!props.fullscreen,
@@ -61,30 +68,64 @@ var widget_body_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
61
68
  setProps: props.setProps,
62
69
  setWorkbook: props.setWorkbook
63
70
  });
71
+ const failed = useErrorBoundary(() => `widget "${props.widget.id}" (${props.widget.type})`, (error) => props.reportError?.(props.widget.id, error));
72
+ const retryRender = () => failed.value = false;
73
+ watch(() => props.widget.props, retryRender, { deep: true });
74
+ watch(data, retryRender);
75
+ const root = ref();
76
+ let refocus = false;
77
+ function retry(again) {
78
+ refocus = !!root.value?.querySelector(".dou-dashboard__status")?.contains(document.activeElement);
79
+ again();
80
+ nextTick(settle);
81
+ }
82
+ /** After a retry: once it has failed or worked, puts focus back on the new retry button if it failed. */
83
+ function settle() {
84
+ if (!refocus || !failed.value && status.value.state === "loading") return;
85
+ refocus = false;
86
+ if (!failed.value && status.value.state !== "error") return;
87
+ const active = document.activeElement;
88
+ if (active && active !== document.body) return;
89
+ root.value?.querySelector(".dou-dashboard__status button")?.focus();
90
+ }
91
+ watch(() => status.value.state, settle, { flush: "post" });
64
92
  return (_ctx, _cache) => {
65
93
  return openBlock(), createElementBlock("div", {
94
+ ref_key: "root",
95
+ ref: root,
66
96
  class: "dou-dashboard__body",
67
97
  "aria-busy": unref(status).state === "loading" || void 0
68
98
  }, [createElementVNode("div", {
69
99
  ref_key: "body",
70
100
  ref: body,
71
101
  class: "dou-dashboard__content"
72
- }, [__props.type ? (openBlock(), createBlock(resolveDynamicComponent(__props.type.component), { key: 0 })) : (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(unref(format)(__props.messages.unknownType, { type: __props.widget.type })), 1))], 512), unref(status).state === "loading" ? (openBlock(), createElementBlock("div", _hoisted_3, [createVNode(unref(DouSpinner), {
102
+ }, [unref(failed) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [], 64)) : __props.type ? (openBlock(), createBlock(resolveDynamicComponent(__props.type.component), { key: 1 })) : (openBlock(), createElementBlock("div", _hoisted_2, toDisplayString(unref(format)(__props.messages.unknownType, { type: __props.widget.type })), 1))], 512), unref(failed) ? (openBlock(), createElementBlock("div", _hoisted_3, [
103
+ createVNode(unref(AlertCircleIcon), { class: "dou-dashboard__status-icon" }),
104
+ createElementVNode("span", null, toDisplayString(__props.messages.renderError), 1),
105
+ createVNode(unref(DouButton), {
106
+ size: "sm",
107
+ variant: "soft",
108
+ onClick: _cache[0] || (_cache[0] = ($event) => retry(retryRender))
109
+ }, {
110
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.retry), 1)]),
111
+ _: 1
112
+ })
113
+ ])) : unref(status).state === "loading" ? (openBlock(), createElementBlock("div", _hoisted_4, [createVNode(unref(DouSpinner), {
73
114
  size: "sm",
74
115
  label: __props.messages.loading
75
- }, null, 8, ["label"])])) : unref(status).state === "error" ? (openBlock(), createElementBlock("div", _hoisted_4, [
116
+ }, null, 8, ["label"])])) : unref(status).state === "error" ? (openBlock(), createElementBlock("div", _hoisted_5, [
76
117
  createVNode(unref(AlertCircleIcon), { class: "dou-dashboard__status-icon" }),
77
118
  createElementVNode("span", null, toDisplayString(unref(status).message || __props.messages.error), 1),
78
119
  unref(status).retry ? (openBlock(), createBlock(unref(DouButton), {
79
120
  key: 0,
80
121
  size: "sm",
81
122
  variant: "soft",
82
- onClick: _cache[0] || (_cache[0] = ($event) => unref(status).retry())
123
+ onClick: _cache[1] || (_cache[1] = ($event) => retry(() => unref(status).retry?.()))
83
124
  }, {
84
125
  default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.retry), 1)]),
85
126
  _: 1
86
127
  })) : createCommentVNode("", true)
87
- ])) : unref(status).state === "empty" ? (openBlock(), createElementBlock("div", _hoisted_5, [createVNode(unref(DouEmpty), {
128
+ ])) : unref(status).state === "empty" ? (openBlock(), createElementBlock("div", _hoisted_6, [createVNode(unref(DouEmpty), {
88
129
  size: "sm",
89
130
  title: unref(status).message || __props.messages.empty
90
131
  }, null, 8, ["title"])])) : createCommentVNode("", true)], 8, _hoisted_1);
@@ -1 +1 @@
1
- {"version":3,"file":"widget-body.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_unref","_createElementVNode","_createBlock","_resolveDynamicComponent","_toDisplayString","_createVNode","_withCtx","_createTextVNode","_createCommentVNode"],"sources":["../../src/dashboard/widget-body.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { AlertCircleIcon } from '@dou-ui/icons'\nimport { DouButton, DouEmpty, DouSpinner } from 'dou-ui'\nimport { inject, onBeforeUnmount, onMounted, ref } from 'vue'\nimport type { SheetWorkbook } from '@dou-ui/sheet/core'\nimport type { DashboardWidget } from '../core/types'\nimport type { DashboardMessages } from '../locale'\nimport { format } from '../locale'\nimport { provideWidgetContext } from '../widget/context'\nimport { observersKey } from './observers'\nimport type { DashboardWidgetType } from '../widget/define'\n\ndefineOptions({ name: 'DouDashboardWidgetBody' })\n\nconst props = defineProps<{\n widget: DashboardWidget\n type?: DashboardWidgetType<any>\n editing: boolean\n fullscreen?: boolean\n messages: DashboardMessages\n setProps: (id: string, patch: Record<string, unknown>, options?: { group?: string }) => void\n /** Where the widget's workbook goes, for its export menu; the full-screen copy has none. */\n setWorkbook?: (id: string, get: () => SheetWorkbook | undefined) => () => void\n}>()\n\nconst body = ref<HTMLElement>()\nconst width = ref(0)\nconst height = ref(0)\nconst observers = inject(observersKey)\nlet stop: (() => void) | undefined\nonMounted(() => {\n // not read here: that would lay the page out once per widget. The first\n // observation comes before the page is painted.\n stop = observers?.size(body.value!, (entry) => {\n width.value = entry.contentRect.width\n height.value = entry.contentRect.height\n })\n})\nonBeforeUnmount(() => stop?.())\nconst { status } = provideWidgetContext({\n widget: () => props.widget,\n editing: () => props.editing,\n fullscreen: () => !!props.fullscreen,\n size: { width, height },\n setProps: props.setProps,\n setWorkbook: props.setWorkbook,\n})\n</script>\n\n<template>\n <div class=\"dou-dashboard__body\" :aria-busy=\"status.state === 'loading' || undefined\">\n <div ref=\"body\" class=\"dou-dashboard__content\">\n <component :is=\"type.component\" v-if=\"type\" />\n <div v-else class=\"dou-dashboard__notice\">\n {{ format(messages.unknownType, { type: widget.type }) }}\n </div>\n </div>\n <div v-if=\"status.state === 'loading'\" class=\"dou-dashboard__status is-loading\" role=\"status\">\n <DouSpinner size=\"sm\" :label=\"messages.loading\" />\n </div>\n <div v-else-if=\"status.state === 'error'\" class=\"dou-dashboard__status is-error\" role=\"alert\">\n <AlertCircleIcon class=\"dou-dashboard__status-icon\" />\n <span>{{ status.message || messages.error }}</span>\n <DouButton v-if=\"status.retry\" size=\"sm\" variant=\"soft\" @click=\"status.retry()\">\n {{ messages.retry }}\n </DouButton>\n </div>\n <div v-else-if=\"status.state === 'empty'\" class=\"dou-dashboard__status is-empty\">\n <DouEmpty size=\"sm\" :title=\"status.message || messages.empty\" />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,QAAQ;EAWd,MAAM,OAAO,IAAiB;EAC9B,MAAM,QAAQ,IAAI,CAAC;EACnB,MAAM,SAAS,IAAI,CAAC;EACpB,MAAM,YAAY,OAAO,YAAY;EACrC,IAAI;EACJ,gBAAgB;GAGd,OAAO,WAAW,KAAK,KAAK,QAAS,UAAU;IAC7C,MAAM,QAAQ,MAAM,YAAY;IAChC,OAAO,QAAQ,MAAM,YAAY;GACnC,CAAC;EACH,CAAC;EACD,sBAAsB,OAAO,CAAC;EAC9B,MAAM,EAAE,WAAW,qBAAqB;GACtC,cAAc,MAAM;GACpB,eAAe,MAAM;GACrB,kBAAkB,CAAC,CAAC,MAAM;GAC1B,MAAM;IAAE;IAAO;GAAO;GACtB,UAAU,MAAM;GAChB,aAAa,MAAM;EACrB,CAAC;;GAIC,OAAAA,UAAA,GAAAC,mBAoBM,OAAA;IApBD,OAAM;IAAuB,aAAWC,MAAA,MAAA,CAAM,CAAC,UAAK,aAAkB,KAAA;G,IACzEC,mBAKM,OAAA;IALG,SAAA;IAAJ,KAAI;IAAO,OAAM;G,IACkB,QAAA,QAAtCH,UAAA,GAAAI,YAA8CC,wBAA9B,QAAA,KAAK,SAAS,GAAA,EAAA,KAAA,EAAA,CAAA,MAC9BL,UAAA,GAAAC,mBAEM,OAFN,YAEMK,gBADDJ,MAAA,MAAA,CAAM,CAAC,QAAA,SAAS,aAAW,EAAA,MAAU,QAAA,OAAO,KAAI,CAAA,CAAA,GAAA,CAAA,E,SAG5CA,MAAA,MAAA,CAAM,CAAC,UAAK,aAAvBF,UAAA,GAAAC,mBAEM,OAFN,YAEM,CADJM,YAAkDL,MAAA,UAAA,GAAA;IAAtC,MAAK;IAAM,OAAO,QAAA,SAAS;G,4BAEzBA,MAAA,MAAA,CAAM,CAAC,UAAK,WAA5BF,UAAA,GAAAC,mBAMM,OANN,YAMM;IALJM,YAAsDL,MAAA,eAAA,GAAA,EAArC,OAAM,6BAA4B,CAAA;IACnDC,mBAAmD,QAAA,MAAAG,gBAA1CJ,MAAA,MAAA,CAAM,CAAC,WAAW,QAAA,SAAS,KAAK,GAAA,CAAA;IACxBA,MAAA,MAAA,CAAM,CAAC,SAAxBF,UAAA,GAAAI,YAEYF,MAAA,SAAA,GAAA;;KAFmB,MAAK;KAAK,SAAQ;KAAQ,SAAK,OAAA,OAAA,OAAA,MAAA,WAAEA,MAAA,MAAA,CAAM,CAAC,MAAK;;KAC1E,SAAAM,cAAoB,CAAjBC,gBAAAH,gBAAA,QAAA,SAAS,KAAK,GAAA,CAAA,C;;;G,MAGLJ,MAAA,MAAA,CAAM,CAAC,UAAK,WAA5BF,UAAA,GAAAC,mBAEM,OAFN,YAEM,CADJM,YAAgEL,MAAA,QAAA,GAAA;IAAtD,MAAK;IAAM,OAAOA,MAAA,MAAA,CAAM,CAAC,WAAW,QAAA,SAAS"}
1
+ {"version":3,"file":"widget-body.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_unref","_createElementVNode","_Fragment","_createBlock","_resolveDynamicComponent","_toDisplayString","_createVNode","_withCtx","_createTextVNode","_createCommentVNode"],"sources":["../../src/dashboard/widget-body.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { AlertCircleIcon } from '@dou-ui/icons'\nimport { DouButton, DouEmpty, DouSpinner } from 'dou-ui'\nimport { inject, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useErrorBoundary } from './error-boundary'\nimport type { SheetWorkbook } from '@dou-ui/sheet/core'\nimport type { DashboardWidget } from '../core/types'\nimport type { DashboardMessages } from '../locale'\nimport { format } from '../locale'\nimport { provideWidgetContext } from '../widget/context'\nimport { observersKey } from './observers'\nimport type { DashboardWidgetType } from '../widget/define'\n\ndefineOptions({ name: 'DouDashboardWidgetBody' })\n\nconst props = defineProps<{\n widget: DashboardWidget\n type?: DashboardWidgetType<any>\n editing: boolean\n fullscreen?: boolean\n messages: DashboardMessages\n setProps: (id: string, patch: Record<string, unknown>, options?: { group?: string }) => void\n /** Where the widget's workbook goes, for its export menu; the full-screen copy has none. */\n setWorkbook?: (id: string, get: () => SheetWorkbook | undefined) => () => void\n /** Told when the widget's content breaks, for the dashboard's `widgetError`. */\n reportError?: (id: string, error: unknown) => void\n}>()\n\nconst body = ref<HTMLElement>()\nconst width = ref(0)\nconst height = ref(0)\nconst observers = inject(observersKey)\nlet stop: (() => void) | undefined\nonMounted(() => {\n // not read here: that would lay the page out once per widget. The first\n // observation comes before the page is painted.\n stop = observers?.size(body.value!, (entry) => {\n width.value = entry.contentRect.width\n height.value = entry.contentRect.height\n })\n})\nonBeforeUnmount(() => stop?.())\nconst { status, data } = provideWidgetContext({\n widget: () => props.widget,\n editing: () => props.editing,\n fullscreen: () => !!props.fullscreen,\n size: { width, height },\n setProps: props.setProps,\n setWorkbook: props.setWorkbook,\n})\n\n// A widget that throws while it sets up or draws, e.g. for props from JSON\n// it can't use, shows an error in its own card; the other widgets and the\n// page go on. It tries again when its props or data change, or on retry.\nconst failed = useErrorBoundary(\n () => `widget \"${props.widget.id}\" (${props.widget.type})`,\n (error) => props.reportError?.(props.widget.id, error),\n)\nconst retryRender = () => (failed.value = false)\nwatch(() => props.widget.props, retryRender, { deep: true })\nwatch(data, retryRender)\n\n// A retry that fails again brings back a new retry button: focus moves to\n// it, rather than falling to the page, if it was on the old one and\n// nothing took it meanwhile.\nconst root = ref<HTMLElement>()\nlet refocus = false\nfunction retry(again: () => void) {\n refocus = !!root.value?.querySelector('.dou-dashboard__status')?.contains(document.activeElement)\n again()\n nextTick(settle)\n}\n/** After a retry: once it has failed or worked, puts focus back on the new retry button if it failed. */\nfunction settle() {\n if (!refocus || (!failed.value && status.value.state === 'loading')) return\n refocus = false\n if (!failed.value && status.value.state !== 'error') return\n const active = document.activeElement\n if (active && active !== document.body) return\n root.value?.querySelector<HTMLElement>('.dou-dashboard__status button')?.focus()\n}\n// data loads later: settle when it fails or arrives\nwatch(() => status.value.state, settle, { flush: 'post' })\n</script>\n\n<template>\n <div ref=\"root\" class=\"dou-dashboard__body\" :aria-busy=\"status.state === 'loading' || undefined\">\n <div ref=\"body\" class=\"dou-dashboard__content\">\n <template v-if=\"failed\" />\n <component :is=\"type.component\" v-else-if=\"type\" />\n <div v-else class=\"dou-dashboard__notice\">\n {{ format(messages.unknownType, { type: widget.type }) }}\n </div>\n </div>\n <div v-if=\"failed\" class=\"dou-dashboard__status is-error\" role=\"alert\">\n <AlertCircleIcon class=\"dou-dashboard__status-icon\" />\n <span>{{ messages.renderError }}</span>\n <DouButton size=\"sm\" variant=\"soft\" @click=\"retry(retryRender)\">\n {{ messages.retry }}\n </DouButton>\n </div>\n <div\n v-else-if=\"status.state === 'loading'\"\n class=\"dou-dashboard__status is-loading\"\n role=\"status\"\n >\n <DouSpinner size=\"sm\" :label=\"messages.loading\" />\n </div>\n <div v-else-if=\"status.state === 'error'\" class=\"dou-dashboard__status is-error\" role=\"alert\">\n <AlertCircleIcon class=\"dou-dashboard__status-icon\" />\n <span>{{ status.message || messages.error }}</span>\n <DouButton\n v-if=\"status.retry\"\n size=\"sm\"\n variant=\"soft\"\n @click=\"retry(() => status.retry?.())\"\n >\n {{ messages.retry }}\n </DouButton>\n </div>\n <div v-else-if=\"status.state === 'empty'\" class=\"dou-dashboard__status is-empty\">\n <DouEmpty size=\"sm\" :title=\"status.message || messages.empty\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -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 CommentButton from './comment-button.vue'\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 <CommentButton :id=\"id\" :comments=\"frame.comments\" :messages=\"messages\" />\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":""}
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 CommentButton from './comment-button.vue'\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 <CommentButton :id=\"id\" :comments=\"frame.comments\" :messages=\"messages\" />\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 :report-error=\"frame.reportError\"\n />\n </div>\n</template>\n"],"mappings":""}
@@ -290,14 +290,16 @@ var widget_frame_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ def
290
290
  editing: editing.value,
291
291
  messages: messages.value,
292
292
  "set-props": unref(frame).setProps,
293
- "set-workbook": unref(frame).setWorkbook
293
+ "set-workbook": unref(frame).setWorkbook,
294
+ "report-error": unref(frame).reportError
294
295
  }, null, 8, [
295
296
  "widget",
296
297
  "type",
297
298
  "editing",
298
299
  "messages",
299
300
  "set-props",
300
- "set-workbook"
301
+ "set-workbook",
302
+ "report-error"
301
303
  ])) : createCommentVNode("", true)
302
304
  ], 6)) : createCommentVNode("", true)], 64);
303
305
  };
@@ -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","CommentButton","_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 CommentButton from './comment-button.vue'\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 <CommentButton :id=\"id\" :comments=\"frame.comments\" :messages=\"messages\" />\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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"}
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","CommentButton","_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 CommentButton from './comment-button.vue'\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 <CommentButton :id=\"id\" :comments=\"frame.comments\" :messages=\"messages\" />\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 :report-error=\"frame.reportError\"\n />\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"widget-settings.js","names":["_sfc_main"],"sources":["../../src/dashboard/widget-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport type { DashboardWidget } from '../core/types'\nimport { provideWidgetContext } from '../widget/context'\nimport type { DashboardWidgetType } from '../widget/define'\n\ndefineOptions({ name: 'DouDashboardWidgetSettings' })\n\nconst props = defineProps<{\n widget: DashboardWidget\n type: DashboardWidgetType<any>\n setProps: (id: string, patch: Record<string, unknown>, options?: { group?: string }) => void\n}>()\nconst emit = defineEmits<{ 'update:props': [props: Record<string, unknown>] }>()\n\n// the settings form can read the widget the same way its content does\nprovideWidgetContext({\n widget: () => props.widget,\n editing: () => true,\n fullscreen: () => false,\n size: { width: ref(0), height: ref(0) },\n setProps: props.setProps,\n})\n</script>\n\n<template>\n <component\n :is=\"type.settings\"\n :model-value=\"widget.props ?? {}\"\n @update:model-value=\"(value: Record<string, unknown>) => emit('update:props', value)\"\n />\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"widget-settings.js","names":["_sfc_main"],"sources":["../../src/dashboard/widget-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { AlertCircleIcon } from '@dou-ui/icons'\nimport { DouButton } from 'dou-ui'\nimport { ref, watch } from 'vue'\nimport type { DashboardWidget } from '../core/types'\nimport type { DashboardMessages } from '../locale'\nimport { provideWidgetContext } from '../widget/context'\nimport type { DashboardWidgetType } from '../widget/define'\nimport { useErrorBoundary } from './error-boundary'\n\ndefineOptions({ name: 'DouDashboardWidgetSettings' })\n\nconst props = defineProps<{\n widget: DashboardWidget\n type: DashboardWidgetType<any>\n messages: DashboardMessages\n setProps: (id: string, patch: Record<string, unknown>, options?: { group?: string }) => void\n /** Told when the settings form breaks, for the dashboard's `widgetError`. */\n reportError?: (id: string, error: unknown) => void\n}>()\nconst emit = defineEmits<{ 'update:props': [props: Record<string, unknown>] }>()\n\n// the settings form can read the widget the same way its content does\nconst { data } = provideWidgetContext({\n widget: () => props.widget,\n editing: () => true,\n fullscreen: () => false,\n size: { width: ref(0), height: ref(0) },\n setProps: props.setProps,\n})\n\n// a settings form that breaks shows an error in the drawer, not to the app;\n// the title field above it still works\nconst failed = useErrorBoundary(\n () => `settings of widget \"${props.widget.id}\" (${props.widget.type})`,\n (error) => props.reportError?.(props.widget.id, error),\n)\nconst retry = () => (failed.value = false)\nwatch(() => props.widget.props, retry, { deep: true })\nwatch(data, retry)\n</script>\n\n<template>\n <div v-if=\"failed\" class=\"dou-dashboard__settings-error\" role=\"alert\">\n <AlertCircleIcon class=\"dou-dashboard__status-icon\" />\n <span>{{ messages.settingsError }}</span>\n <DouButton size=\"sm\" variant=\"soft\" @click=\"retry\">{{ messages.retry }}</DouButton>\n </div>\n <component\n :is=\"type.settings\"\n v-else\n :model-value=\"widget.props ?? {}\"\n @update:model-value=\"(value: Record<string, unknown>) => emit('update:props', value)\"\n />\n</template>\n"],"mappings":""}
@@ -1,19 +1,29 @@
1
+ import { useErrorBoundary } from "./error-boundary.js";
1
2
  import { provideWidgetContext } from "../widget/context.js";
2
- import { createBlock, defineComponent, openBlock, ref, resolveDynamicComponent } from "vue";
3
+ import { DouButton } from "dou-ui";
4
+ import { createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, resolveDynamicComponent, toDisplayString, unref, watch, withCtx } from "vue";
5
+ import { AlertCircleIcon } from "@dou-ui/icons";
3
6
  // src/dashboard/widget-settings.vue?vue&type=script&setup=true&lang.ts
7
+ var _hoisted_1 = {
8
+ key: 0,
9
+ class: "dou-dashboard__settings-error",
10
+ role: "alert"
11
+ };
4
12
  var widget_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
5
13
  name: "DouDashboardWidgetSettings",
6
14
  __name: "widget-settings",
7
15
  props: {
8
16
  widget: {},
9
17
  type: {},
10
- setProps: { type: Function }
18
+ messages: {},
19
+ setProps: { type: Function },
20
+ reportError: { type: Function }
11
21
  },
12
22
  emits: ["update:props"],
13
23
  setup(__props, { emit: __emit }) {
14
24
  const props = __props;
15
25
  const emit = __emit;
16
- provideWidgetContext({
26
+ const { data } = provideWidgetContext({
17
27
  widget: () => props.widget,
18
28
  editing: () => true,
19
29
  fullscreen: () => false,
@@ -23,11 +33,27 @@ var widget_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
23
33
  },
24
34
  setProps: props.setProps
25
35
  });
36
+ const failed = useErrorBoundary(() => `settings of widget "${props.widget.id}" (${props.widget.type})`, (error) => props.reportError?.(props.widget.id, error));
37
+ const retry = () => failed.value = false;
38
+ watch(() => props.widget.props, retry, { deep: true });
39
+ watch(data, retry);
26
40
  return (_ctx, _cache) => {
27
- return openBlock(), createBlock(resolveDynamicComponent(__props.type.settings), {
41
+ return unref(failed) ? (openBlock(), createElementBlock("div", _hoisted_1, [
42
+ createVNode(unref(AlertCircleIcon), { class: "dou-dashboard__status-icon" }),
43
+ createElementVNode("span", null, toDisplayString(__props.messages.settingsError), 1),
44
+ createVNode(unref(DouButton), {
45
+ size: "sm",
46
+ variant: "soft",
47
+ onClick: retry
48
+ }, {
49
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.messages.retry), 1)]),
50
+ _: 1
51
+ })
52
+ ])) : (openBlock(), createBlock(resolveDynamicComponent(__props.type.settings), {
53
+ key: 1,
28
54
  "model-value": __props.widget.props ?? {},
29
55
  "onUpdate:modelValue": _cache[0] || (_cache[0] = (value) => emit("update:props", value))
30
- }, null, 8, ["model-value"]);
56
+ }, null, 8, ["model-value"]));
31
57
  };
32
58
  }
33
59
  });
@@ -1 +1 @@
1
- {"version":3,"file":"widget-settings.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent"],"sources":["../../src/dashboard/widget-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport type { DashboardWidget } from '../core/types'\nimport { provideWidgetContext } from '../widget/context'\nimport type { DashboardWidgetType } from '../widget/define'\n\ndefineOptions({ name: 'DouDashboardWidgetSettings' })\n\nconst props = defineProps<{\n widget: DashboardWidget\n type: DashboardWidgetType<any>\n setProps: (id: string, patch: Record<string, unknown>, options?: { group?: string }) => void\n}>()\nconst emit = defineEmits<{ 'update:props': [props: Record<string, unknown>] }>()\n\n// the settings form can read the widget the same way its content does\nprovideWidgetContext({\n widget: () => props.widget,\n editing: () => true,\n fullscreen: () => false,\n size: { width: ref(0), height: ref(0) },\n setProps: props.setProps,\n})\n</script>\n\n<template>\n <component\n :is=\"type.settings\"\n :model-value=\"widget.props ?? {}\"\n @update:model-value=\"(value: Record<string, unknown>) => emit('update:props', value)\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;EAQA,MAAM,QAAQ;EAKd,MAAM,OAAO;EAGb,qBAAqB;GACnB,cAAc,MAAM;GACpB,eAAe;GACf,kBAAkB;GAClB,MAAM;IAAE,OAAO,IAAI,CAAC;IAAG,QAAQ,IAAI,CAAC;GAAE;GACtC,UAAU,MAAM;EAClB,CAAC;;GAIC,OAAAA,UAAA,GAAAC,YAIEC,wBAHK,QAAA,KAAK,QAAQ,GAAA;IACjB,eAAa,QAAA,OAAO,SAAK,CAAA;IACzB,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAmC,KAAI,gBAAiB,KAAK"}
1
+ {"version":3,"file":"widget-settings.vue_vue_type_script_setup_true_lang.js","names":["_unref","_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_withCtx","_createTextVNode","_createBlock","_resolveDynamicComponent"],"sources":["../../src/dashboard/widget-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { AlertCircleIcon } from '@dou-ui/icons'\nimport { DouButton } from 'dou-ui'\nimport { ref, watch } from 'vue'\nimport type { DashboardWidget } from '../core/types'\nimport type { DashboardMessages } from '../locale'\nimport { provideWidgetContext } from '../widget/context'\nimport type { DashboardWidgetType } from '../widget/define'\nimport { useErrorBoundary } from './error-boundary'\n\ndefineOptions({ name: 'DouDashboardWidgetSettings' })\n\nconst props = defineProps<{\n widget: DashboardWidget\n type: DashboardWidgetType<any>\n messages: DashboardMessages\n setProps: (id: string, patch: Record<string, unknown>, options?: { group?: string }) => void\n /** Told when the settings form breaks, for the dashboard's `widgetError`. */\n reportError?: (id: string, error: unknown) => void\n}>()\nconst emit = defineEmits<{ 'update:props': [props: Record<string, unknown>] }>()\n\n// the settings form can read the widget the same way its content does\nconst { data } = provideWidgetContext({\n widget: () => props.widget,\n editing: () => true,\n fullscreen: () => false,\n size: { width: ref(0), height: ref(0) },\n setProps: props.setProps,\n})\n\n// a settings form that breaks shows an error in the drawer, not to the app;\n// the title field above it still works\nconst failed = useErrorBoundary(\n () => `settings of widget \"${props.widget.id}\" (${props.widget.type})`,\n (error) => props.reportError?.(props.widget.id, error),\n)\nconst retry = () => (failed.value = false)\nwatch(() => props.widget.props, retry, { deep: true })\nwatch(data, retry)\n</script>\n\n<template>\n <div v-if=\"failed\" class=\"dou-dashboard__settings-error\" role=\"alert\">\n <AlertCircleIcon class=\"dou-dashboard__status-icon\" />\n <span>{{ messages.settingsError }}</span>\n <DouButton size=\"sm\" variant=\"soft\" @click=\"retry\">{{ messages.retry }}</DouButton>\n </div>\n <component\n :is=\"type.settings\"\n v-else\n :model-value=\"widget.props ?? {}\"\n @update:model-value=\"(value: Record<string, unknown>) => emit('update:props', value)\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EAYA,MAAM,QAAQ;EAQd,MAAM,OAAO;EAGb,MAAM,EAAE,SAAS,qBAAqB;GACpC,cAAc,MAAM;GACpB,eAAe;GACf,kBAAkB;GAClB,MAAM;IAAE,OAAO,IAAI,CAAC;IAAG,QAAQ,IAAI,CAAC;GAAE;GACtC,UAAU,MAAM;EAClB,CAAC;EAID,MAAM,SAAS,uBACP,uBAAuB,MAAM,OAAO,GAAG,KAAK,MAAM,OAAO,KAAK,KACnE,UAAU,MAAM,cAAc,MAAM,OAAO,IAAI,KAAK,CACvD;EACA,MAAM,cAAe,OAAO,QAAQ;EACpC,YAAY,MAAM,OAAO,OAAO,OAAO,EAAE,MAAM,KAAK,CAAC;EACrD,MAAM,MAAM,KAAK;;GAIJ,OAAAA,MAAA,MAAA,KAAXC,UAAA,GAAAC,mBAIM,OAJN,YAIM;IAHJC,YAAsDH,MAAA,eAAA,GAAA,EAArC,OAAM,6BAA4B,CAAA;IACnDI,mBAAyC,QAAA,MAAAC,gBAAhC,QAAA,SAAS,aAAa,GAAA,CAAA;IAC/BF,YAAmFH,MAAA,SAAA,GAAA;KAAxE,MAAK;KAAK,SAAQ;KAAQ,SAAO;;KAAO,SAAAM,cAAoB,CAAjBC,gBAAAF,gBAAA,QAAA,SAAS,KAAK,GAAA,CAAA,C;;;G,OAEtEJ,UAAA,GAAAO,YAKEC,wBAJK,QAAA,KAAK,QAAQ,GAAA;;IAEjB,eAAa,QAAA,OAAO,SAAK,CAAA;IACzB,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAmC,KAAI,gBAAiB,KAAK"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["GridLayout","GridLayoutHandle","Dashboard","DashboardPalette","DashboardFilterBar"],"sources":["../src/index.ts"],"sourcesContent":["import { withInstall } from 'dou-ui'\nimport GridLayout from './grid/grid-layout.vue'\nimport GridLayoutHandle from './grid/grid-handle.vue'\nimport Dashboard from './dashboard/dashboard.vue'\nimport DashboardPalette from './dashboard/palette.vue'\nimport DashboardFilterBar from './dashboard/filter-bar.vue'\n\nexport const DouGridLayout = withInstall(GridLayout)\nexport const DouGridLayoutHandle = withInstall(GridLayoutHandle)\nexport const DouDashboard = withInstall(Dashboard)\nexport const DouDashboardPalette = withInstall(DashboardPalette)\nexport const DouDashboardFilterBar = withInstall(DashboardFilterBar)\n\nexport type {\n DashboardAddOptions,\n DashboardEmits,\n DashboardExportErrorEvent,\n DashboardExportOptions,\n DashboardSaveOptions,\n DashboardCommentAnchor,\n DashboardExpose,\n DashboardFilterBarProps,\n DashboardPaletteProps,\n DashboardProps,\n} from './dashboard/types'\nexport type { DashboardDocument, DashboardPlace, DashboardWidget } from './core/types'\nexport { checkDocument, emptyDocument, isDashboardPlace, migrateDocument } from './core/document'\nexport type { CheckDocumentOptions, DocumentProblem } from './core/document'\nexport { applySteps, DashboardTransaction, replaceWidgets, sameValue } from './core/transaction'\nexport type { ReplaceWidgetsOptions } from './core/transaction'\nexport type {\n DashboardCollaboration,\n DashboardCollaborationHost,\n DashboardPeer,\n DashboardPresence,\n DashboardPresenceAction,\n} from './core/collaboration'\nexport type {\n DashboardStep,\n DashboardTransactionMeta,\n DashboardWidgetPatch,\n} from './core/transaction'\nexport { DashboardHistory } from './core/history'\nexport { defineDashboardWidget } from './widget/define'\nexport type { DashboardWidgetSize, DashboardWidgetType } from './widget/define'\nexport { useDashboardWidget } from './widget/context'\nexport { isEmptyFilter } from './data/filters'\nexport type { DashboardImageOptions } from './dashboard/export'\nexport type {\n DashboardDateRangeFilterField,\n DashboardFilterField,\n DashboardFilters,\n DashboardLinkedFilter,\n DashboardSearchFilterField,\n DashboardSelectFilterField,\n DashboardSetFilterOptions,\n DashboardSourceContext,\n DashboardSourceLoad,\n DashboardSourceOptions,\n DashboardSources,\n} from './data/types'\nexport type {\n DashboardWidgetContext,\n DashboardWidgetState,\n DashboardWidgetStatus,\n} from './widget/context'\n\nexport type {\n GridChangeEvent,\n GridChangeReason,\n GridDragEndEvent,\n GridDragEvent,\n GridDropEvent,\n GridDropItem,\n GridItemSlotProps,\n GridLayoutEmits,\n GridLayoutExpose,\n GridLayoutProps,\n GridLayouts,\n GridPlace,\n GridResizeHandle,\n} from './grid/types'\nexport {\n compactLayout,\n deriveLayout,\n findPlace,\n fitItem,\n layoutHeight,\n moveItem,\n moveItemBy,\n normalizeLayout,\n overlaps,\n resizeItem,\n resizeItemBy,\n} from './layout'\nexport type { GridCompact, GridItem, GridLayoutOptions, GridPosition, GridSize } from './layout'\nexport { dashboardLocales, useDashboardMessages } from './locale'\nexport type { DashboardMessages, DashboardMessagesOverride } from './locale'\n\ndeclare module 'vue' {\n export interface GlobalComponents {\n DouGridLayout: typeof DouGridLayout\n DouGridLayoutHandle: typeof DouGridLayoutHandle\n DouDashboard: typeof DouDashboard\n DouDashboardPalette: typeof DouDashboardPalette\n DouDashboardFilterBar: typeof DouDashboardFilterBar\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAOA,IAAa,gBAAgB,YAAYA,mBAAU;AACnD,IAAa,sBAAsB,YAAYC,mBAAgB;AAC/D,IAAa,eAAe,YAAYC,iBAAS;AACjD,IAAa,sBAAsB,YAAYC,eAAgB;AAC/D,IAAa,wBAAwB,YAAYC,kBAAkB"}
1
+ {"version":3,"file":"index.js","names":["GridLayout","GridLayoutHandle","Dashboard","DashboardPalette","DashboardFilterBar"],"sources":["../src/index.ts"],"sourcesContent":["import { withInstall } from 'dou-ui'\nimport GridLayout from './grid/grid-layout.vue'\nimport GridLayoutHandle from './grid/grid-handle.vue'\nimport Dashboard from './dashboard/dashboard.vue'\nimport DashboardPalette from './dashboard/palette.vue'\nimport DashboardFilterBar from './dashboard/filter-bar.vue'\n\nexport const DouGridLayout = withInstall(GridLayout)\nexport const DouGridLayoutHandle = withInstall(GridLayoutHandle)\nexport const DouDashboard = withInstall(Dashboard)\nexport const DouDashboardPalette = withInstall(DashboardPalette)\nexport const DouDashboardFilterBar = withInstall(DashboardFilterBar)\n\nexport type {\n DashboardAddOptions,\n DashboardEmits,\n DashboardExportErrorEvent,\n DashboardWidgetErrorEvent,\n DashboardExportOptions,\n DashboardSaveOptions,\n DashboardCommentAnchor,\n DashboardExpose,\n DashboardFilterBarProps,\n DashboardPaletteProps,\n DashboardProps,\n} from './dashboard/types'\nexport type { DashboardDocument, DashboardPlace, DashboardWidget } from './core/types'\nexport { checkDocument, emptyDocument, isDashboardPlace, migrateDocument } from './core/document'\nexport type { CheckDocumentOptions, DocumentProblem } from './core/document'\nexport { applySteps, DashboardTransaction, replaceWidgets, sameValue } from './core/transaction'\nexport type { ReplaceWidgetsOptions } from './core/transaction'\nexport type {\n DashboardCollaboration,\n DashboardCollaborationHost,\n DashboardPeer,\n DashboardPresence,\n DashboardPresenceAction,\n} from './core/collaboration'\nexport type {\n DashboardStep,\n DashboardTransactionMeta,\n DashboardWidgetPatch,\n} from './core/transaction'\nexport { DashboardHistory } from './core/history'\nexport { defineDashboardWidget } from './widget/define'\nexport type { DashboardWidgetSize, DashboardWidgetType } from './widget/define'\nexport { useDashboardWidget } from './widget/context'\nexport { isEmptyFilter } from './data/filters'\nexport type { DashboardImageOptions } from './dashboard/export'\nexport type {\n DashboardDateRangeFilterField,\n DashboardFilterField,\n DashboardFilters,\n DashboardLinkedFilter,\n DashboardSearchFilterField,\n DashboardSelectFilterField,\n DashboardSetFilterOptions,\n DashboardSourceContext,\n DashboardSourceLoad,\n DashboardSourceOptions,\n DashboardSources,\n} from './data/types'\nexport type {\n DashboardWidgetContext,\n DashboardWidgetState,\n DashboardWidgetStatus,\n} from './widget/context'\n\nexport type {\n GridChangeEvent,\n GridChangeReason,\n GridDragEndEvent,\n GridDragEvent,\n GridDropEvent,\n GridDropItem,\n GridItemSlotProps,\n GridLayoutEmits,\n GridLayoutExpose,\n GridLayoutProps,\n GridLayouts,\n GridPlace,\n GridResizeHandle,\n} from './grid/types'\nexport {\n compactLayout,\n deriveLayout,\n findPlace,\n fitItem,\n layoutHeight,\n moveItem,\n moveItemBy,\n normalizeLayout,\n overlaps,\n resizeItem,\n resizeItemBy,\n} from './layout'\nexport type { GridCompact, GridItem, GridLayoutOptions, GridPosition, GridSize } from './layout'\nexport { dashboardLocales, useDashboardMessages } from './locale'\nexport type { DashboardMessages, DashboardMessagesOverride } from './locale'\n\ndeclare module 'vue' {\n export interface GlobalComponents {\n DouGridLayout: typeof DouGridLayout\n DouGridLayoutHandle: typeof DouGridLayoutHandle\n DouDashboard: typeof DouDashboard\n DouDashboardPalette: typeof DouDashboardPalette\n DouDashboardFilterBar: typeof DouDashboardFilterBar\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAOA,IAAa,gBAAgB,YAAYA,mBAAU;AACnD,IAAa,sBAAsB,YAAYC,mBAAgB;AAC/D,IAAa,eAAe,YAAYC,iBAAS;AACjD,IAAa,sBAAsB,YAAYC,eAAgB;AAC/D,IAAa,wBAAwB,YAAYC,kBAAkB"}
package/dist/locale.js CHANGED
@@ -31,6 +31,8 @@ var zhCN = {
31
31
  unknownType: "没有注册类型为 {type} 的格子",
32
32
  loading: "加载中",
33
33
  error: "加载失败",
34
+ renderError: "无法显示",
35
+ settingsError: "无法显示设置",
34
36
  empty: "暂无数据",
35
37
  retry: "重试",
36
38
  emptyTitle: "还没有格子",
@@ -105,6 +107,8 @@ var zhTW = {
105
107
  unknownType: "沒有註冊類型為 {type} 的格子",
106
108
  loading: "載入中",
107
109
  error: "載入失敗",
110
+ renderError: "無法顯示",
111
+ settingsError: "無法顯示設定",
108
112
  empty: "暫無資料",
109
113
  retry: "重試",
110
114
  emptyTitle: "還沒有格子",
@@ -179,6 +183,8 @@ var en = {
179
183
  unknownType: "No widget type “{type}” is registered",
180
184
  loading: "Loading",
181
185
  error: "Couldn’t load",
186
+ renderError: "Couldn’t display",
187
+ settingsError: "Couldn’t display the settings",
182
188
  empty: "No data",
183
189
  retry: "Retry",
184
190
  emptyTitle: "No widgets yet",
@@ -1 +1 @@
1
- {"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface DashboardMessages {\n /** The grid layout's accessible name. */\n layout: string\n /** What an item of the grid is called by a screen reader. */\n item: string\n /** Read after an item's name while the layout can be edited. */\n itemHint: string\n /** An item that can't be moved: `{item}`. */\n locked: string\n /** An item's place: `{x}` `{y}` (from 1), `{w}` `{h}` (in columns and rows). */\n position: string\n /** An item's place when the grid has one column: `{n}` of `{count}` (from 1). */\n order: string\n /** An item picked up with the keyboard: `{item}` and `{position}`. */\n grabbed: string\n /** An item put down, with the keyboard or the pointer: `{item}` and `{position}`. */\n dropped: string\n /** A move or resize undone with Escape (or a drop outside the grid): `{item}`. */\n cancelled: string\n /** The handle in an item's corner. */\n resize: string\n /** The dashboard's accessible name. */\n dashboard: string\n /** The menu button in a widget's title bar. */\n widgetMenu: string\n /** Menu items. */\n settings: string\n fullscreen: string\n /** The menu of file types a widget's content can be exported as. */\n export: string\n /** A failed export, over the widget's content: `{name}` (the file), `{reason}`. */\n exportFailed: string\n /** Read out once the file is saved: `{name}`. */\n exported: string\n /** Why a widget can't be exported: it has no data, such as a chart without its fields. */\n nothingToExport: string\n duplicate: string\n remove: string\n /** The comment button and the card of a widget's discussions. */\n comment: string\n /** The comment button of a widget with discussions; `{count}` is how many are open. */\n comments: string\n /** The settings drawer's title: `{title}`. */\n settingsTitle: string\n /** The title field in the settings drawer. */\n titleField: string\n /** Read when a widget is added, copied or removed: `{item}`. */\n added: string\n removed: string\n /** A widget whose type isn't registered: `{type}`. */\n unknownType: string\n /** A widget's status. */\n loading: string\n error: string\n empty: string\n retry: string\n /** A dashboard without widgets, while editing. */\n emptyTitle: string\n emptyHint: string\n /** The list of widgets to add. */\n palette: string\n /** A widget in that list: `{label}`. */\n paletteItem: string\n /** In the title bar of a widget that set a filter: `{value}`. */\n filteredBy: string\n peerMoving: string\n peerResizing: string\n peerSettings: string\n /** The button clearing that filter: `{value}`. */\n clearFilter: string\n /** The filter bar's accessible name. */\n filterBar: string\n /** A filter set by a widget, in the filter bar: `{title}` and `{value}`. */\n linkedFilter: string\n /** Clears every filter. */\n clearFilters: string\n /** Settings of the built-in widgets. */\n source: string\n noSource: string\n field: string\n value: string\n prefix: string\n suffix: string\n precision: string\n trend: string\n delta: string\n /** The change under a number: `{value}`, e.g. `+12.5%`. */\n deltaText: string\n text: string\n textSize: string\n sizeSmall: string\n sizeMedium: string\n sizeLarge: string\n columns: string\n /** The title of a table column, while it has none: `{field}`. */\n columnTitle: string\n chartKind: string\n chartLine: string\n chartArea: string\n chartBar: string\n chartPie: string\n xField: string\n yFields: string\n stacked: string\n horizontal: string\n /** The filter set by clicking a chart. */\n chartFilter: string\n chartFilterHint: string\n /** Whether clicking a pivot table's cell filters the other widgets. */\n pivotFilter: string\n}\n\nconst zhCN: DashboardMessages = {\n layout: '网格布局',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向键移动、Shift 加方向键调整大小',\n locked: '{item} 已锁定,不能移动',\n position: '第 {x} 列第 {y} 行,宽 {w} 列,高 {h} 行',\n order: '第 {n} 个,共 {count} 个',\n grabbed: '已拿起 {item},{position}。方向键移动,Shift 加方向键调整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原处',\n resize: '调整大小',\n dashboard: '仪表盘',\n widgetMenu: '格子操作',\n settings: '设置',\n fullscreen: '全屏查看',\n export: '导出',\n exportFailed: '无法导出 {name}:{reason}',\n exported: '已导出 {name}',\n nothingToExport: '没有可导出的数据',\n duplicate: '复制一份',\n remove: '删除',\n comment: '评论',\n comments: '{count} 条评论',\n settingsTitle: '{title}的设置',\n titleField: '标题',\n added: '已添加 {item}',\n removed: '已删除 {item}',\n unknownType: '没有注册类型为 {type} 的格子',\n loading: '加载中',\n error: '加载失败',\n empty: '暂无数据',\n retry: '重试',\n emptyTitle: '还没有格子',\n emptyHint: '从列表里拖进来,或点一下添加',\n palette: '添加格子',\n paletteItem: '添加{label}',\n filteredBy: '已按 {value} 筛选',\n peerMoving: '{name} 正在移动',\n peerResizing: '{name} 正在调整大小',\n peerSettings: '{name} 正在修改设置',\n clearFilter: '清除筛选:{value}',\n filterBar: '筛选',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除筛选',\n source: '数据源',\n noSource: '不使用数据源',\n field: '字段',\n value: '数值',\n prefix: '前缀',\n suffix: '后缀',\n precision: '小数位数',\n trend: '迷你图字段',\n delta: '变化率字段',\n deltaText: '较上期 {value}',\n text: '文字',\n textSize: '字号',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '列',\n columnTitle: '{field} 的标题',\n chartKind: '图表',\n chartLine: '折线图',\n chartArea: '面积图',\n chartBar: '柱状图',\n chartPie: '饼图',\n xField: '分类或时间',\n yFields: '数值',\n stacked: '堆叠',\n horizontal: '横向',\n chartFilter: '点击时筛选',\n chartFilterHint: '点图表里的一项时,用这个名字筛选其他格子;留空则不筛选',\n pivotFilter: '点击单元格时,按它所在的分组筛选其他格子',\n}\n\nconst zhTW: DashboardMessages = {\n layout: '網格版面',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向鍵移動、Shift 加方向鍵調整大小',\n locked: '{item} 已鎖定,無法移動',\n position: '第 {x} 欄第 {y} 列,寬 {w} 欄,高 {h} 列',\n order: '第 {n} 個,共 {count} 個',\n grabbed: '已拿起 {item},{position}。方向鍵移動,Shift 加方向鍵調整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原處',\n resize: '調整大小',\n dashboard: '儀表板',\n widgetMenu: '格子操作',\n settings: '設定',\n fullscreen: '全螢幕檢視',\n export: '匯出',\n exportFailed: '無法匯出 {name}:{reason}',\n exported: '已匯出 {name}',\n nothingToExport: '沒有可匯出的資料',\n duplicate: '複製一份',\n remove: '刪除',\n comment: '評論',\n comments: '{count} 則評論',\n settingsTitle: '{title}的設定',\n titleField: '標題',\n added: '已新增 {item}',\n removed: '已刪除 {item}',\n unknownType: '沒有註冊類型為 {type} 的格子',\n loading: '載入中',\n error: '載入失敗',\n empty: '暫無資料',\n retry: '重試',\n emptyTitle: '還沒有格子',\n emptyHint: '從清單拖進來,或點一下新增',\n palette: '新增格子',\n paletteItem: '新增{label}',\n filteredBy: '已按 {value} 篩選',\n peerMoving: '{name} 正在移動',\n peerResizing: '{name} 正在調整大小',\n peerSettings: '{name} 正在修改設定',\n clearFilter: '清除篩選:{value}',\n filterBar: '篩選',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除篩選',\n source: '資料來源',\n noSource: '不使用資料來源',\n field: '欄位',\n value: '數值',\n prefix: '前綴',\n suffix: '後綴',\n precision: '小數位數',\n trend: '迷你圖欄位',\n delta: '變化率欄位',\n deltaText: '較上期 {value}',\n text: '文字',\n textSize: '字號',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '欄',\n columnTitle: '{field} 的標題',\n chartKind: '圖表',\n chartLine: '折線圖',\n chartArea: '面積圖',\n chartBar: '長條圖',\n chartPie: '圓餅圖',\n xField: '分類或時間',\n yFields: '數值',\n stacked: '堆疊',\n horizontal: '橫向',\n chartFilter: '點擊時篩選',\n chartFilterHint: '點圖表裡的一項時,用這個名字篩選其他格子;留空則不篩選',\n pivotFilter: '點擊儲存格時,依其所在的分組篩選其他格子',\n}\n\nconst en: DashboardMessages = {\n layout: 'Grid layout',\n item: 'tile',\n itemHint: 'Press Enter to pick up, then arrow keys to move and Shift with arrow keys to resize',\n locked: '{item} is locked and can’t be moved',\n position: 'column {x}, row {y}, {w} columns wide, {h} rows high',\n order: '{n} of {count}',\n grabbed:\n 'Picked up {item}, {position}. Arrow keys move, Shift with arrow keys resizes, Enter puts down, Escape cancels',\n dropped: 'Put down {item}, {position}',\n cancelled: 'Cancelled, {item} is back where it was',\n resize: 'Resize',\n dashboard: 'Dashboard',\n widgetMenu: 'Widget actions',\n settings: 'Settings',\n fullscreen: 'View full screen',\n export: 'Export',\n exportFailed: \"Couldn't export {name}: {reason}\",\n exported: 'Exported {name}',\n nothingToExport: 'There is no data to export',\n duplicate: 'Duplicate',\n remove: 'Remove',\n comment: 'Comment',\n comments: '{count} comments',\n settingsTitle: '{title} settings',\n titleField: 'Title',\n added: 'Added {item}',\n removed: 'Removed {item}',\n unknownType: 'No widget type “{type}” is registered',\n loading: 'Loading',\n error: 'Couldn’t load',\n empty: 'No data',\n retry: 'Retry',\n emptyTitle: 'No widgets yet',\n emptyHint: 'Drag one in from the list, or click to add it',\n palette: 'Add widget',\n paletteItem: 'Add {label}',\n filteredBy: 'Filtered by {value}',\n peerMoving: '{name} is moving it',\n peerResizing: '{name} is resizing it',\n peerSettings: '{name} is changing its settings',\n clearFilter: 'Clear filter: {value}',\n filterBar: 'Filters',\n linkedFilter: '{title}: {value}',\n clearFilters: 'Clear filters',\n source: 'Source',\n noSource: 'No source',\n field: 'Field',\n value: 'Value',\n prefix: 'Prefix',\n suffix: 'Suffix',\n precision: 'Decimal places',\n trend: 'Sparkline field',\n delta: 'Change field',\n deltaText: '{value} vs. last period',\n text: 'Text',\n textSize: 'Size',\n sizeSmall: 'Small',\n sizeMedium: 'Medium',\n sizeLarge: 'Large',\n columns: 'Columns',\n columnTitle: 'Title of {field}',\n chartKind: 'Chart',\n chartLine: 'Line',\n chartArea: 'Area',\n chartBar: 'Bar',\n chartPie: 'Pie',\n xField: 'Category or time',\n yFields: 'Values',\n stacked: 'Stacked',\n horizontal: 'Horizontal',\n chartFilter: 'Filter on click',\n chartFilterHint:\n 'Clicking an item filters the other widgets by this name; leave empty to not filter',\n pivotFilter: 'Clicking a cell filters the other widgets by its groups',\n}\n\nexport const dashboardLocales: Record<string, DashboardMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type DashboardMessagesOverride = Partial<DashboardMessages>\n\n/**\n * The dashboard's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useDashboardMessages(\n override?: MaybeRefOrGetter<DashboardMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<DashboardMessages>(() => {\n const name = locale.value.name\n const base =\n dashboardLocales[name] ??\n dashboardLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":"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"}
1
+ {"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface DashboardMessages {\n /** The grid layout's accessible name. */\n layout: string\n /** What an item of the grid is called by a screen reader. */\n item: string\n /** Read after an item's name while the layout can be edited. */\n itemHint: string\n /** An item that can't be moved: `{item}`. */\n locked: string\n /** An item's place: `{x}` `{y}` (from 1), `{w}` `{h}` (in columns and rows). */\n position: string\n /** An item's place when the grid has one column: `{n}` of `{count}` (from 1). */\n order: string\n /** An item picked up with the keyboard: `{item}` and `{position}`. */\n grabbed: string\n /** An item put down, with the keyboard or the pointer: `{item}` and `{position}`. */\n dropped: string\n /** A move or resize undone with Escape (or a drop outside the grid): `{item}`. */\n cancelled: string\n /** The handle in an item's corner. */\n resize: string\n /** The dashboard's accessible name. */\n dashboard: string\n /** The menu button in a widget's title bar. */\n widgetMenu: string\n /** Menu items. */\n settings: string\n fullscreen: string\n /** The menu of file types a widget's content can be exported as. */\n export: string\n /** A failed export, over the widget's content: `{name}` (the file), `{reason}`. */\n exportFailed: string\n /** Read out once the file is saved: `{name}`. */\n exported: string\n /** Why a widget can't be exported: it has no data, such as a chart without its fields. */\n nothingToExport: string\n duplicate: string\n remove: string\n /** The comment button and the card of a widget's discussions. */\n comment: string\n /** The comment button of a widget with discussions; `{count}` is how many are open. */\n comments: string\n /** The settings drawer's title: `{title}`. */\n settingsTitle: string\n /** The title field in the settings drawer. */\n titleField: string\n /** Read when a widget is added, copied or removed: `{item}`. */\n added: string\n removed: string\n /** A widget whose type isn't registered: `{type}`. */\n unknownType: string\n /** A widget's status. */\n loading: string\n error: string\n /** A widget that failed to show, e.g. for props it can't use. */\n renderError: string\n /** A widget's settings form that failed to show. */\n settingsError: string\n empty: string\n retry: string\n /** A dashboard without widgets, while editing. */\n emptyTitle: string\n emptyHint: string\n /** The list of widgets to add. */\n palette: string\n /** A widget in that list: `{label}`. */\n paletteItem: string\n /** In the title bar of a widget that set a filter: `{value}`. */\n filteredBy: string\n peerMoving: string\n peerResizing: string\n peerSettings: string\n /** The button clearing that filter: `{value}`. */\n clearFilter: string\n /** The filter bar's accessible name. */\n filterBar: string\n /** A filter set by a widget, in the filter bar: `{title}` and `{value}`. */\n linkedFilter: string\n /** Clears every filter. */\n clearFilters: string\n /** Settings of the built-in widgets. */\n source: string\n noSource: string\n field: string\n value: string\n prefix: string\n suffix: string\n precision: string\n trend: string\n delta: string\n /** The change under a number: `{value}`, e.g. `+12.5%`. */\n deltaText: string\n text: string\n textSize: string\n sizeSmall: string\n sizeMedium: string\n sizeLarge: string\n columns: string\n /** The title of a table column, while it has none: `{field}`. */\n columnTitle: string\n chartKind: string\n chartLine: string\n chartArea: string\n chartBar: string\n chartPie: string\n xField: string\n yFields: string\n stacked: string\n horizontal: string\n /** The filter set by clicking a chart. */\n chartFilter: string\n chartFilterHint: string\n /** Whether clicking a pivot table's cell filters the other widgets. */\n pivotFilter: string\n}\n\nconst zhCN: DashboardMessages = {\n layout: '网格布局',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向键移动、Shift 加方向键调整大小',\n locked: '{item} 已锁定,不能移动',\n position: '第 {x} 列第 {y} 行,宽 {w} 列,高 {h} 行',\n order: '第 {n} 个,共 {count} 个',\n grabbed: '已拿起 {item},{position}。方向键移动,Shift 加方向键调整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原处',\n resize: '调整大小',\n dashboard: '仪表盘',\n widgetMenu: '格子操作',\n settings: '设置',\n fullscreen: '全屏查看',\n export: '导出',\n exportFailed: '无法导出 {name}:{reason}',\n exported: '已导出 {name}',\n nothingToExport: '没有可导出的数据',\n duplicate: '复制一份',\n remove: '删除',\n comment: '评论',\n comments: '{count} 条评论',\n settingsTitle: '{title}的设置',\n titleField: '标题',\n added: '已添加 {item}',\n removed: '已删除 {item}',\n unknownType: '没有注册类型为 {type} 的格子',\n loading: '加载中',\n error: '加载失败',\n renderError: '无法显示',\n settingsError: '无法显示设置',\n empty: '暂无数据',\n retry: '重试',\n emptyTitle: '还没有格子',\n emptyHint: '从列表里拖进来,或点一下添加',\n palette: '添加格子',\n paletteItem: '添加{label}',\n filteredBy: '已按 {value} 筛选',\n peerMoving: '{name} 正在移动',\n peerResizing: '{name} 正在调整大小',\n peerSettings: '{name} 正在修改设置',\n clearFilter: '清除筛选:{value}',\n filterBar: '筛选',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除筛选',\n source: '数据源',\n noSource: '不使用数据源',\n field: '字段',\n value: '数值',\n prefix: '前缀',\n suffix: '后缀',\n precision: '小数位数',\n trend: '迷你图字段',\n delta: '变化率字段',\n deltaText: '较上期 {value}',\n text: '文字',\n textSize: '字号',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '列',\n columnTitle: '{field} 的标题',\n chartKind: '图表',\n chartLine: '折线图',\n chartArea: '面积图',\n chartBar: '柱状图',\n chartPie: '饼图',\n xField: '分类或时间',\n yFields: '数值',\n stacked: '堆叠',\n horizontal: '横向',\n chartFilter: '点击时筛选',\n chartFilterHint: '点图表里的一项时,用这个名字筛选其他格子;留空则不筛选',\n pivotFilter: '点击单元格时,按它所在的分组筛选其他格子',\n}\n\nconst zhTW: DashboardMessages = {\n layout: '網格版面',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向鍵移動、Shift 加方向鍵調整大小',\n locked: '{item} 已鎖定,無法移動',\n position: '第 {x} 欄第 {y} 列,寬 {w} 欄,高 {h} 列',\n order: '第 {n} 個,共 {count} 個',\n grabbed: '已拿起 {item},{position}。方向鍵移動,Shift 加方向鍵調整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原處',\n resize: '調整大小',\n dashboard: '儀表板',\n widgetMenu: '格子操作',\n settings: '設定',\n fullscreen: '全螢幕檢視',\n export: '匯出',\n exportFailed: '無法匯出 {name}:{reason}',\n exported: '已匯出 {name}',\n nothingToExport: '沒有可匯出的資料',\n duplicate: '複製一份',\n remove: '刪除',\n comment: '評論',\n comments: '{count} 則評論',\n settingsTitle: '{title}的設定',\n titleField: '標題',\n added: '已新增 {item}',\n removed: '已刪除 {item}',\n unknownType: '沒有註冊類型為 {type} 的格子',\n loading: '載入中',\n error: '載入失敗',\n renderError: '無法顯示',\n settingsError: '無法顯示設定',\n empty: '暫無資料',\n retry: '重試',\n emptyTitle: '還沒有格子',\n emptyHint: '從清單拖進來,或點一下新增',\n palette: '新增格子',\n paletteItem: '新增{label}',\n filteredBy: '已按 {value} 篩選',\n peerMoving: '{name} 正在移動',\n peerResizing: '{name} 正在調整大小',\n peerSettings: '{name} 正在修改設定',\n clearFilter: '清除篩選:{value}',\n filterBar: '篩選',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除篩選',\n source: '資料來源',\n noSource: '不使用資料來源',\n field: '欄位',\n value: '數值',\n prefix: '前綴',\n suffix: '後綴',\n precision: '小數位數',\n trend: '迷你圖欄位',\n delta: '變化率欄位',\n deltaText: '較上期 {value}',\n text: '文字',\n textSize: '字號',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '欄',\n columnTitle: '{field} 的標題',\n chartKind: '圖表',\n chartLine: '折線圖',\n chartArea: '面積圖',\n chartBar: '長條圖',\n chartPie: '圓餅圖',\n xField: '分類或時間',\n yFields: '數值',\n stacked: '堆疊',\n horizontal: '橫向',\n chartFilter: '點擊時篩選',\n chartFilterHint: '點圖表裡的一項時,用這個名字篩選其他格子;留空則不篩選',\n pivotFilter: '點擊儲存格時,依其所在的分組篩選其他格子',\n}\n\nconst en: DashboardMessages = {\n layout: 'Grid layout',\n item: 'tile',\n itemHint: 'Press Enter to pick up, then arrow keys to move and Shift with arrow keys to resize',\n locked: '{item} is locked and can’t be moved',\n position: 'column {x}, row {y}, {w} columns wide, {h} rows high',\n order: '{n} of {count}',\n grabbed:\n 'Picked up {item}, {position}. Arrow keys move, Shift with arrow keys resizes, Enter puts down, Escape cancels',\n dropped: 'Put down {item}, {position}',\n cancelled: 'Cancelled, {item} is back where it was',\n resize: 'Resize',\n dashboard: 'Dashboard',\n widgetMenu: 'Widget actions',\n settings: 'Settings',\n fullscreen: 'View full screen',\n export: 'Export',\n exportFailed: \"Couldn't export {name}: {reason}\",\n exported: 'Exported {name}',\n nothingToExport: 'There is no data to export',\n duplicate: 'Duplicate',\n remove: 'Remove',\n comment: 'Comment',\n comments: '{count} comments',\n settingsTitle: '{title} settings',\n titleField: 'Title',\n added: 'Added {item}',\n removed: 'Removed {item}',\n unknownType: 'No widget type “{type}” is registered',\n loading: 'Loading',\n error: 'Couldn’t load',\n renderError: 'Couldn’t display',\n settingsError: 'Couldn’t display the settings',\n empty: 'No data',\n retry: 'Retry',\n emptyTitle: 'No widgets yet',\n emptyHint: 'Drag one in from the list, or click to add it',\n palette: 'Add widget',\n paletteItem: 'Add {label}',\n filteredBy: 'Filtered by {value}',\n peerMoving: '{name} is moving it',\n peerResizing: '{name} is resizing it',\n peerSettings: '{name} is changing its settings',\n clearFilter: 'Clear filter: {value}',\n filterBar: 'Filters',\n linkedFilter: '{title}: {value}',\n clearFilters: 'Clear filters',\n source: 'Source',\n noSource: 'No source',\n field: 'Field',\n value: 'Value',\n prefix: 'Prefix',\n suffix: 'Suffix',\n precision: 'Decimal places',\n trend: 'Sparkline field',\n delta: 'Change field',\n deltaText: '{value} vs. last period',\n text: 'Text',\n textSize: 'Size',\n sizeSmall: 'Small',\n sizeMedium: 'Medium',\n sizeLarge: 'Large',\n columns: 'Columns',\n columnTitle: 'Title of {field}',\n chartKind: 'Chart',\n chartLine: 'Line',\n chartArea: 'Area',\n chartBar: 'Bar',\n chartPie: 'Pie',\n xField: 'Category or time',\n yFields: 'Values',\n stacked: 'Stacked',\n horizontal: 'Horizontal',\n chartFilter: 'Filter on click',\n chartFilterHint:\n 'Clicking an item filters the other widgets by this name; leave empty to not filter',\n pivotFilter: 'Clicking a cell filters the other widgets by its groups',\n}\n\nexport const dashboardLocales: Record<string, DashboardMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type DashboardMessagesOverride = Partial<DashboardMessages>\n\n/**\n * The dashboard's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useDashboardMessages(\n override?: MaybeRefOrGetter<DashboardMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<DashboardMessages>(() => {\n const name = locale.value.name\n const base =\n dashboardLocales[name] ??\n dashboardLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pivot-settings.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivotFields } from '@dou-ui/pivot'\nimport type { PivotField } from '@dou-ui/pivot'\nimport { DouSwitch } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from '../widgets/settings-field.vue'\nimport { rowsOf } from '../widgets/shared'\nimport SourceField from '../widgets/source-field.vue'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotSettings' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\nconst model = defineModel<PivotWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst rows = computed(() => rowsOf(data.value, model.value.path))\nconst set = (patch: Partial<PivotWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField :model-value=\"model.source\" @update:model-value=\"(source) => set({ source })\" />\n <SettingsField v-if=\"rows.length\" :label=\"messages.field\">\n <DouPivotFields\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"model.config\"\n :drawer=\"false\"\n @update:config=\"(config) => set({ config })\"\n />\n </SettingsField>\n <DouSwitch\n :model-value=\"!!model.filter\"\n @update:model-value=\"(filter) => set({ filter: filter || undefined })\"\n >\n {{ messages.pivotFilter }}\n </DouSwitch>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"pivot-settings.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivotFields } from '@dou-ui/pivot'\nimport type { PivotField } from '@dou-ui/pivot'\nimport { DouSwitch } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from '../widgets/settings-field.vue'\nimport { rowsOf } from '../widgets/shared'\nimport SourceField from '../widgets/source-field.vue'\nimport type { PivotWidgetProps } from './types'\nimport { pivotPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardPivotSettings' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\nconst model = defineModel<PivotWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => pivotPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst rows = computed(() => rowsOf(data.value, view.value.path))\nconst set = (patch: Partial<PivotWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField :model-value=\"view.source\" @update:model-value=\"(source) => set({ source })\" />\n <SettingsField v-if=\"rows.length\" :label=\"messages.field\">\n <DouPivotFields\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"view.config\"\n :drawer=\"false\"\n @update:config=\"(config) => set({ config })\"\n />\n </SettingsField>\n <DouSwitch\n :model-value=\"!!view.filter\"\n @update:model-value=\"(filter) => set({ filter: filter || undefined })\"\n >\n {{ messages.pivotFilter }}\n </DouSwitch>\n </div>\n</template>\n"],"mappings":""}