@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 +1 @@
1
- {"version":3,"file":"shared.js","names":[],"sources":["../../src/widgets/shared.ts"],"sourcesContent":["import type { SheetValue, SheetWorkbook } from '@dou-ui/sheet/core'\n\n/** The value at a dotted path, e.g. `total.amount`; the data itself for an empty path. */\nexport function valueAt(data: unknown, path: string | undefined): unknown {\n if (!path) return data\n let value = data\n for (const key of path.split('.')) {\n if (value == null || typeof value !== 'object') return undefined\n value = (value as Record<string, unknown>)[key]\n }\n return value\n}\n\n/** The rows of a source's data: the data when it is a list, or the list at `path`. */\nexport function rowsOf(data: unknown, path?: string): Record<string, unknown>[] {\n const value = valueAt(data, path)\n return Array.isArray(value) ? (value as Record<string, unknown>[]) : []\n}\n\n/** The keys of the first row of a list, or of an object: the fields to pick from in settings. */\nexport function fieldsOf(data: unknown): string[] {\n const first = Array.isArray(data) ? data[0] : data\n return first && typeof first === 'object' && !Array.isArray(first) ? Object.keys(first) : []\n}\n\n/** The keys whose value in the first row is a number. */\nexport function numberFieldsOf(data: unknown): string[] {\n const first = Array.isArray(data) ? data[0] : data\n return fieldsOf(data).filter((key) => typeof (first as Record<string, unknown>)[key] === 'number')\n}\n\n/** A filter value from a value of the data: dates as `YYYY-MM-DD`, so the filters stay JSON. */\nconst pad = (n: number) => String(n).padStart(2, '0')\n\nexport function filterValueOf(value: unknown): unknown {\n if (!(value instanceof Date)) return value\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`\n}\n\n/** A value of the data as a sheet cell's: dates as `YYYY-MM-DD`, text starting with `=` kept as text. */\nfunction sheetValueOf(value: unknown): SheetValue {\n if (value == null) return null\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value === 'boolean') return value\n const text = value instanceof Date ? (filterValueOf(value) as string) : String(value)\n return text.startsWith('=') ? `'${text}` : text\n}\n\n/**\n * Rows of data as a workbook, for the dashboard's export menu: one sheet,\n * a bold head row with the columns' titles, a row per row of data. An\n * empty `name` takes the widget's title.\n */\nexport function rowsToWorkbook(\n name: string,\n columns: readonly { key: string; title: string; width?: number }[],\n rows: readonly Record<string, unknown>[],\n): SheetWorkbook {\n const colSizes: Record<number, number> = {}\n columns.forEach((column, i) => column.width && (colSizes[i] = Math.round(column.width)))\n return {\n version: 1,\n sheets: [\n {\n name,\n cells: [\n columns.map((column) => ({ value: sheetValueOf(column.title), style: 'head' })),\n ...rows.map((row) => columns.map((column) => sheetValueOf(row[column.key]))),\n ],\n freeze: { rows: 1, cols: 0 },\n colSizes,\n },\n ],\n styles: { head: { bold: true } },\n }\n}\n"],"mappings":";;AAGA,SAAgB,QAAQ,MAAe,MAAmC;CACxE,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG;EACjC,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU,OAAO,KAAA;EACvD,QAAS,MAAkC;CAC7C;CACA,OAAO;AACT;;AAGA,SAAgB,OAAO,MAAe,MAA0C;CAC9E,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,OAAO,MAAM,QAAQ,KAAK,IAAK,QAAsC,CAAC;AACxE;;AAGA,SAAgB,SAAS,MAAyB;CAChD,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;CAC9C,OAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI,CAAC;AAC7F;;AAGA,SAAgB,eAAe,MAAyB;CACtD,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;CAC9C,OAAO,SAAS,IAAI,CAAC,CAAC,QAAQ,QAAQ,OAAQ,MAAkC,SAAS,QAAQ;AACnG;;AAGA,IAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;AAEpD,SAAgB,cAAc,OAAyB;CACrD,IAAI,EAAE,iBAAiB,OAAO,OAAO;CACrC,OAAO,GAAG,MAAM,YAAY,EAAE,GAAG,IAAI,MAAM,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,MAAM,QAAQ,CAAC;AACnF;;AAGA,SAAS,aAAa,OAA4B;CAChD,IAAI,SAAS,MAAM,OAAO;CAC1B,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;CACvE,IAAI,OAAO,UAAU,WAAW,OAAO;CACvC,MAAM,OAAO,iBAAiB,OAAQ,cAAc,KAAK,IAAe,OAAO,KAAK;CACpF,OAAO,KAAK,WAAW,GAAG,IAAI,IAAI,SAAS;AAC7C;;;;;;AAOA,SAAgB,eACd,MACA,SACA,MACe;CACf,MAAM,WAAmC,CAAC;CAC1C,QAAQ,SAAS,QAAQ,MAAM,OAAO,UAAU,SAAS,KAAK,KAAK,MAAM,OAAO,KAAK,EAAE;CACvF,OAAO;EACL,SAAS;EACT,QAAQ,CACN;GACE;GACA,OAAO,CACL,QAAQ,KAAK,YAAY;IAAE,OAAO,aAAa,OAAO,KAAK;IAAG,OAAO;GAAO,EAAE,GAC9E,GAAG,KAAK,KAAK,QAAQ,QAAQ,KAAK,WAAW,aAAa,IAAI,OAAO,IAAI,CAAC,CAAC,CAC7E;GACA,QAAQ;IAAE,MAAM;IAAG,MAAM;GAAE;GAC3B;EACF,CACF;EACA,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,EAAE;CACjC;AACF"}
1
+ {"version":3,"file":"shared.js","names":[],"sources":["../../src/widgets/shared.ts"],"sourcesContent":["import type { SheetValue, SheetWorkbook } from '@dou-ui/sheet/core'\n\n/**\n * The value at a dotted path, e.g. `total.amount`; the data itself for an\n * empty path. A path that isn't text, e.g. a number in JSON written by hand\n * or by a program, finds nothing.\n */\nexport function valueAt(data: unknown, path: unknown): unknown {\n if (path === undefined || path === null || path === '') return data\n if (typeof path !== 'string') return undefined\n let value = data\n for (const key of path.split('.')) {\n if (value == null || typeof value !== 'object') return undefined\n value = (value as Record<string, unknown>)[key]\n }\n return value\n}\n\n/** The rows of a source's data: the data when it is a list, or the list at `path`. Items that aren't objects are left out. */\nexport function rowsOf(data: unknown, path?: unknown): Record<string, unknown>[] {\n const value = valueAt(data, path)\n if (!Array.isArray(value)) return []\n return value.every(isRecord) ? value : value.filter(isRecord)\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n value !== null && typeof value === 'object'\n\n/*\n * A widget's props come from JSON that types don't check, often written by a\n * program or an AI. These read one prop as the type it is meant to be; any\n * other value counts as not set, so a widget never throws on it.\n */\n\n/** Text, or not set. */\nexport const textOf = (value: unknown): string | undefined =>\n typeof value === 'string' ? value : undefined\n\n/** A list of texts: the texts in it, or none. */\nexport const textsOf = (value: unknown): string[] =>\n Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []\n\n/** A finite number, or text that is one (`'12'`, as a number read from data); otherwise not set. */\nexport function numberOf(value: unknown): number | undefined {\n const n =\n typeof value === 'number'\n ? value\n : typeof value === 'string' && value.trim()\n ? Number(value)\n : Number.NaN\n return Number.isFinite(n) ? n : undefined\n}\n\n/** On only for `true`: `'no'` or `1` don't turn a switch on. */\nexport const flagOf = (value: unknown): boolean => value === true\n\n/** A plain object, not a list; otherwise not set. */\nexport const recordOf = (value: unknown): Record<string, unknown> | undefined =>\n isRecord(value) && !Array.isArray(value) ? value : undefined\n\n/** One of the values listed, or not set. */\nexport const oneOf = <T extends string>(value: unknown, values: readonly T[]): T | undefined =>\n values.includes(value as T) ? (value as T) : undefined\n\n/** The keys of the first row of a list, or of an object: the fields to pick from in settings. */\nexport function fieldsOf(data: unknown): string[] {\n const first = Array.isArray(data) ? data[0] : data\n return first && typeof first === 'object' && !Array.isArray(first) ? Object.keys(first) : []\n}\n\n/** The keys whose value in the first row is a number. */\nexport function numberFieldsOf(data: unknown): string[] {\n const first = Array.isArray(data) ? data[0] : data\n return fieldsOf(data).filter((key) => typeof (first as Record<string, unknown>)[key] === 'number')\n}\n\n/** A filter value from a value of the data: dates as `YYYY-MM-DD`, so the filters stay JSON. */\nconst pad = (n: number) => String(n).padStart(2, '0')\n\nexport function filterValueOf(value: unknown): unknown {\n if (!(value instanceof Date)) return value\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`\n}\n\n/** A value of the data as a sheet cell's: dates as `YYYY-MM-DD`, text starting with `=` kept as text. */\nfunction sheetValueOf(value: unknown): SheetValue {\n if (value == null) return null\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value === 'boolean') return value\n const text = value instanceof Date ? (filterValueOf(value) as string) : String(value)\n return text.startsWith('=') ? `'${text}` : text\n}\n\n/**\n * Rows of data as a workbook, for the dashboard's export menu: one sheet,\n * a bold head row with the columns' titles, a row per row of data. An\n * empty `name` takes the widget's title.\n */\nexport function rowsToWorkbook(\n name: string,\n columns: readonly { key: string; title: string; width?: number }[],\n rows: readonly Record<string, unknown>[],\n): SheetWorkbook {\n const colSizes: Record<number, number> = {}\n columns.forEach((column, i) => column.width && (colSizes[i] = Math.round(column.width)))\n return {\n version: 1,\n sheets: [\n {\n name,\n cells: [\n columns.map((column) => ({ value: sheetValueOf(column.title), style: 'head' })),\n ...rows.map((row) => columns.map((column) => sheetValueOf(row[column.key]))),\n ],\n freeze: { rows: 1, cols: 0 },\n colSizes,\n },\n ],\n styles: { head: { bold: true } },\n }\n}\n"],"mappings":";;;;;;AAOA,SAAgB,QAAQ,MAAe,MAAwB;CAC7D,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,SAAS,IAAI,OAAO;CAC/D,IAAI,OAAO,SAAS,UAAU,OAAO,KAAA;CACrC,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG;EACjC,IAAI,SAAS,QAAQ,OAAO,UAAU,UAAU,OAAO,KAAA;EACvD,QAAS,MAAkC;CAC7C;CACA,OAAO;AACT;;AAGA,SAAgB,OAAO,MAAe,MAA2C;CAC/E,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;CACnC,OAAO,MAAM,MAAM,QAAQ,IAAI,QAAQ,MAAM,OAAO,QAAQ;AAC9D;AAEA,IAAM,YAAY,UAChB,UAAU,QAAQ,OAAO,UAAU;;AASrC,IAAa,UAAU,UACrB,OAAO,UAAU,WAAW,QAAQ,KAAA;;AAGtC,IAAa,WAAW,UACtB,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAAI,CAAC;;AAG7F,SAAgB,SAAS,OAAoC;CAC3D,MAAM,IACJ,OAAO,UAAU,WACb,QACA,OAAO,UAAU,YAAY,MAAM,KAAK,IACtC,OAAO,KAAK,IACZ;CACR,OAAO,OAAO,SAAS,CAAC,IAAI,IAAI,KAAA;AAClC;;AAGA,IAAa,UAAU,UAA4B,UAAU;;AAG7D,IAAa,YAAY,UACvB,SAAS,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAA;;AAGrD,IAAa,SAA2B,OAAgB,WACtD,OAAO,SAAS,KAAU,IAAK,QAAc,KAAA;;AAG/C,SAAgB,SAAS,MAAyB;CAChD,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;CAC9C,OAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI,CAAC;AAC7F;;AAGA,SAAgB,eAAe,MAAyB;CACtD,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,KAAK;CAC9C,OAAO,SAAS,IAAI,CAAC,CAAC,QAAQ,QAAQ,OAAQ,MAAkC,SAAS,QAAQ;AACnG;;AAGA,IAAM,OAAO,MAAc,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;AAEpD,SAAgB,cAAc,OAAyB;CACrD,IAAI,EAAE,iBAAiB,OAAO,OAAO;CACrC,OAAO,GAAG,MAAM,YAAY,EAAE,GAAG,IAAI,MAAM,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,MAAM,QAAQ,CAAC;AACnF;;AAGA,SAAS,aAAa,OAA4B;CAChD,IAAI,SAAS,MAAM,OAAO;CAC1B,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;CACvE,IAAI,OAAO,UAAU,WAAW,OAAO;CACvC,MAAM,OAAO,iBAAiB,OAAQ,cAAc,KAAK,IAAe,OAAO,KAAK;CACpF,OAAO,KAAK,WAAW,GAAG,IAAI,IAAI,SAAS;AAC7C;;;;;;AAOA,SAAgB,eACd,MACA,SACA,MACe;CACf,MAAM,WAAmC,CAAC;CAC1C,QAAQ,SAAS,QAAQ,MAAM,OAAO,UAAU,SAAS,KAAK,KAAK,MAAM,OAAO,KAAK,EAAE;CACvF,OAAO;EACL,SAAS;EACT,QAAQ,CACN;GACE;GACA,OAAO,CACL,QAAQ,KAAK,YAAY;IAAE,OAAO,aAAa,OAAO,KAAK;IAAG,OAAO;GAAO,EAAE,GAC9E,GAAG,KAAK,KAAK,QAAQ,QAAQ,KAAK,WAAW,aAAa,IAAI,OAAO,IAAI,CAAC,CAAC,CAC7E;GACA,QAAQ;IAAE,MAAM;IAAG,MAAM;GAAE;GAC3B;EACF,CACF;EACA,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,EAAE;CACjC;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"stat-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/stat-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouInput, DouInputNumber } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport FieldSelect from './field-select.vue'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { StatWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardStatSettings' })\n\nconst model = defineModel<StatWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst fields = computed(() => fieldsOf(data.value))\nconst set = (patch: Partial<StatWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"model.source\"\n optional\n @update:model-value=\"(source) => set({ source })\"\n />\n <FieldSelect\n v-if=\"model.source\"\n :model-value=\"model.field\"\n :label=\"messages.value\"\n :fields=\"fields\"\n @update:model-value=\"(field) => set({ field: field as string | undefined })\"\n />\n <SettingsField v-else :label=\"messages.value\">\n <DouInputNumber\n :model-value=\"model.value ?? null\"\n :aria-label=\"messages.value\"\n @update:model-value=\"(value) => set({ value: value ?? undefined })\"\n />\n </SettingsField>\n <div class=\"dou-dashboard__field-row\">\n <SettingsField :label=\"messages.prefix\">\n <DouInput\n :model-value=\"model.prefix ?? ''\"\n :aria-label=\"messages.prefix\"\n @update:model-value=\"(prefix) => set({ prefix: prefix || undefined })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.suffix\">\n <DouInput\n :model-value=\"model.suffix ?? ''\"\n :aria-label=\"messages.suffix\"\n @update:model-value=\"(suffix) => set({ suffix: suffix || undefined })\"\n />\n </SettingsField>\n </div>\n <SettingsField :label=\"messages.precision\">\n <DouInputNumber\n :model-value=\"model.precision ?? null\"\n :min=\"0\"\n :max=\"6\"\n :aria-label=\"messages.precision\"\n @update:model-value=\"(precision) => set({ precision: precision ?? undefined })\"\n />\n </SettingsField>\n <template v-if=\"model.source\">\n <FieldSelect\n :model-value=\"model.trend\"\n :label=\"messages.trend\"\n :fields=\"fields\"\n @update:model-value=\"(trend) => set({ trend: trend as string | undefined })\"\n />\n <FieldSelect\n :model-value=\"model.delta\"\n :label=\"messages.delta\"\n :fields=\"fields\"\n @update:model-value=\"(delta) => set({ delta: delta as string | undefined })\"\n />\n </template>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"stat-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/stat-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouInput, DouInputNumber } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport FieldSelect from './field-select.vue'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { StatWidgetProps } from './types'\nimport { statPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardStatSettings' })\n\nconst model = defineModel<StatWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => statPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst fields = computed(() => fieldsOf(data.value))\nconst set = (patch: Partial<StatWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"view.source\"\n optional\n @update:model-value=\"(source) => set({ source })\"\n />\n <FieldSelect\n v-if=\"view.source\"\n :model-value=\"view.field\"\n :label=\"messages.value\"\n :fields=\"fields\"\n @update:model-value=\"(field) => set({ field: field as string | undefined })\"\n />\n <SettingsField v-else :label=\"messages.value\">\n <DouInputNumber\n :model-value=\"view.value ?? null\"\n :aria-label=\"messages.value\"\n @update:model-value=\"(value) => set({ value: value ?? undefined })\"\n />\n </SettingsField>\n <div class=\"dou-dashboard__field-row\">\n <SettingsField :label=\"messages.prefix\">\n <DouInput\n :model-value=\"view.prefix ?? ''\"\n :aria-label=\"messages.prefix\"\n @update:model-value=\"(prefix) => set({ prefix: prefix || undefined })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.suffix\">\n <DouInput\n :model-value=\"view.suffix ?? ''\"\n :aria-label=\"messages.suffix\"\n @update:model-value=\"(suffix) => set({ suffix: suffix || undefined })\"\n />\n </SettingsField>\n </div>\n <SettingsField :label=\"messages.precision\">\n <DouInputNumber\n :model-value=\"view.precision ?? null\"\n :min=\"0\"\n :max=\"6\"\n :aria-label=\"messages.precision\"\n @update:model-value=\"(precision) => set({ precision: precision ?? undefined })\"\n />\n </SettingsField>\n <template v-if=\"view.source\">\n <FieldSelect\n :model-value=\"view.trend\"\n :label=\"messages.trend\"\n :fields=\"fields\"\n @update:model-value=\"(trend) => set({ trend: trend as string | undefined })\"\n />\n <FieldSelect\n :model-value=\"view.delta\"\n :label=\"messages.delta\"\n :fields=\"fields\"\n @update:model-value=\"(delta) => set({ delta: delta as string | undefined })\"\n />\n </template>\n </div>\n</template>\n"],"mappings":""}
@@ -1,6 +1,7 @@
1
1
  import { useDashboardMessages } from "../locale.js";
2
2
  import { useDashboardWidget } from "../widget/context.js";
3
3
  import { fieldsOf } from "./shared.js";
4
+ import { statPropsOf } from "./read-props.js";
4
5
  import settings_field_default from "./settings-field.js";
5
6
  import field_select_default from "./field-select.js";
6
7
  import source_field_default from "./source-field.js";
@@ -19,6 +20,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
19
20
  emits: ["update:modelValue"],
20
21
  setup(__props) {
21
22
  const model = useModel(__props, "modelValue");
23
+ const view = computed(() => statPropsOf(model.value));
22
24
  const messages = useDashboardMessages();
23
25
  const { data } = useDashboardWidget();
24
26
  const fields = computed(() => fieldsOf(data.value));
@@ -29,13 +31,13 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
29
31
  return (_ctx, _cache) => {
30
32
  return openBlock(), createElementBlock("div", _hoisted_1, [
31
33
  createVNode(source_field_default, {
32
- "model-value": model.value.source,
34
+ "model-value": view.value.source,
33
35
  optional: "",
34
36
  "onUpdate:modelValue": _cache[0] || (_cache[0] = (source) => set({ source }))
35
37
  }, null, 8, ["model-value"]),
36
- model.value.source ? (openBlock(), createBlock(field_select_default, {
38
+ view.value.source ? (openBlock(), createBlock(field_select_default, {
37
39
  key: 0,
38
- "model-value": model.value.field,
40
+ "model-value": view.value.field,
39
41
  label: unref(messages).value,
40
42
  fields: fields.value,
41
43
  "onUpdate:modelValue": _cache[1] || (_cache[1] = (field) => set({ field }))
@@ -48,7 +50,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
48
50
  label: unref(messages).value
49
51
  }, {
50
52
  default: withCtx(() => [createVNode(unref(DouInputNumber), {
51
- "model-value": model.value.value ?? null,
53
+ "model-value": view.value.value ?? null,
52
54
  "aria-label": unref(messages).value,
53
55
  "onUpdate:modelValue": _cache[2] || (_cache[2] = (value) => set({ value: value ?? void 0 }))
54
56
  }, null, 8, ["model-value", "aria-label"])]),
@@ -56,14 +58,14 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
56
58
  }, 8, ["label"])),
57
59
  createElementVNode("div", _hoisted_2, [createVNode(settings_field_default, { label: unref(messages).prefix }, {
58
60
  default: withCtx(() => [createVNode(unref(DouInput), {
59
- "model-value": model.value.prefix ?? "",
61
+ "model-value": view.value.prefix ?? "",
60
62
  "aria-label": unref(messages).prefix,
61
63
  "onUpdate:modelValue": _cache[3] || (_cache[3] = (prefix) => set({ prefix: prefix || void 0 }))
62
64
  }, null, 8, ["model-value", "aria-label"])]),
63
65
  _: 1
64
66
  }, 8, ["label"]), createVNode(settings_field_default, { label: unref(messages).suffix }, {
65
67
  default: withCtx(() => [createVNode(unref(DouInput), {
66
- "model-value": model.value.suffix ?? "",
68
+ "model-value": view.value.suffix ?? "",
67
69
  "aria-label": unref(messages).suffix,
68
70
  "onUpdate:modelValue": _cache[4] || (_cache[4] = (suffix) => set({ suffix: suffix || void 0 }))
69
71
  }, null, 8, ["model-value", "aria-label"])]),
@@ -71,7 +73,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
71
73
  }, 8, ["label"])]),
72
74
  createVNode(settings_field_default, { label: unref(messages).precision }, {
73
75
  default: withCtx(() => [createVNode(unref(DouInputNumber), {
74
- "model-value": model.value.precision ?? null,
76
+ "model-value": view.value.precision ?? null,
75
77
  min: 0,
76
78
  max: 6,
77
79
  "aria-label": unref(messages).precision,
@@ -79,8 +81,8 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
79
81
  }, null, 8, ["model-value", "aria-label"])]),
80
82
  _: 1
81
83
  }, 8, ["label"]),
82
- model.value.source ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createVNode(field_select_default, {
83
- "model-value": model.value.trend,
84
+ view.value.source ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createVNode(field_select_default, {
85
+ "model-value": view.value.trend,
84
86
  label: unref(messages).trend,
85
87
  fields: fields.value,
86
88
  "onUpdate:modelValue": _cache[6] || (_cache[6] = (trend) => set({ trend }))
@@ -89,7 +91,7 @@ var stat_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
89
91
  "label",
90
92
  "fields"
91
93
  ]), createVNode(field_select_default, {
92
- "model-value": model.value.delta,
94
+ "model-value": view.value.delta,
93
95
  label: unref(messages).delta,
94
96
  fields: fields.value,
95
97
  "onUpdate:modelValue": _cache[7] || (_cache[7] = (delta) => set({ delta }))
@@ -1 +1 @@
1
- {"version":3,"file":"stat-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SourceField","_createBlock","FieldSelect","_unref","SettingsField","_withCtx","_createElementVNode","_Fragment","_createCommentVNode"],"sources":["../../src/widgets/stat-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouInput, DouInputNumber } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport FieldSelect from './field-select.vue'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { StatWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardStatSettings' })\n\nconst model = defineModel<StatWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst fields = computed(() => fieldsOf(data.value))\nconst set = (patch: Partial<StatWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"model.source\"\n optional\n @update:model-value=\"(source) => set({ source })\"\n />\n <FieldSelect\n v-if=\"model.source\"\n :model-value=\"model.field\"\n :label=\"messages.value\"\n :fields=\"fields\"\n @update:model-value=\"(field) => set({ field: field as string | undefined })\"\n />\n <SettingsField v-else :label=\"messages.value\">\n <DouInputNumber\n :model-value=\"model.value ?? null\"\n :aria-label=\"messages.value\"\n @update:model-value=\"(value) => set({ value: value ?? undefined })\"\n />\n </SettingsField>\n <div class=\"dou-dashboard__field-row\">\n <SettingsField :label=\"messages.prefix\">\n <DouInput\n :model-value=\"model.prefix ?? ''\"\n :aria-label=\"messages.prefix\"\n @update:model-value=\"(prefix) => set({ prefix: prefix || undefined })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.suffix\">\n <DouInput\n :model-value=\"model.suffix ?? ''\"\n :aria-label=\"messages.suffix\"\n @update:model-value=\"(suffix) => set({ suffix: suffix || undefined })\"\n />\n </SettingsField>\n </div>\n <SettingsField :label=\"messages.precision\">\n <DouInputNumber\n :model-value=\"model.precision ?? null\"\n :min=\"0\"\n :max=\"6\"\n :aria-label=\"messages.precision\"\n @update:model-value=\"(precision) => set({ precision: precision ?? undefined })\"\n />\n </SettingsField>\n <template v-if=\"model.source\">\n <FieldSelect\n :model-value=\"model.trend\"\n :label=\"messages.trend\"\n :fields=\"fields\"\n @update:model-value=\"(trend) => set({ trend: trend as string | undefined })\"\n />\n <FieldSelect\n :model-value=\"model.delta\"\n :label=\"messages.delta\"\n :fields=\"fields\"\n @update:model-value=\"(delta) => set({ delta: delta as string | undefined })\"\n />\n </template>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAaA,MAAM,QAAQA,SAA4B,SAAA,YAAmB;EAC7D,MAAM,WAAW,qBAAqB;EACtC,MAAM,EAAE,SAAS,mBAAmB;EACpC,MAAM,SAAS,eAAe,SAAS,KAAK,KAAK,CAAC;EAClD,MAAM,OAAO,UAAqC,MAAM,QAAQ;GAAE,GAAG,MAAM;GAAO,GAAG;EAAM;;GAIzF,OAAAC,UAAA,GAAAC,mBA2DM,OA3DN,YA2DM;IA1DJC,YAIEC,sBAAA;KAHC,eAAa,MAAA,MAAM;KACpB,UAAA;KACC,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAG,OAAM,CAAA;;IAGvC,MAAA,MAAM,UADdH,UAAA,GAAAI,YAMEC,sBAAA;;KAJC,eAAa,MAAA,MAAM;KACnB,OAAOC,MAAA,QAAA,CAAQ,CAAC;KAChB,QAAQ,OAAA;KACR,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAU,MAAK,CAAA;;;;;I,OAEpDN,UAAA,GAAAI,YAMgBG,wBAAA;;KANO,OAAOD,MAAA,QAAA,CAAQ,CAAC;;KACrC,SAAAE,cAIE,CAJFN,YAIEI,MAAA,cAAA,GAAA;MAHC,eAAa,MAAA,MAAM,SAAK;MACxB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAA,OAAU,SAAS,KAAA,EAAS,CAAA;;;;IAGnEG,mBAeM,OAfN,YAeM,CAdJP,YAMgBK,wBAAA,EANA,OAAOD,MAAA,QAAA,CAAQ,CAAC,O;KAC9B,SAAAE,cAIE,CAJFN,YAIEI,MAAA,QAAA,GAAA;MAHC,eAAa,MAAA,MAAM,UAAM;MACzB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAA,QAAW,UAAU,KAAA,EAAS,CAAA;;;I,kBAGtEJ,YAMgBK,wBAAA,EANA,OAAOD,MAAA,QAAA,CAAQ,CAAC,O;KAC9B,SAAAE,cAIE,CAJFN,YAIEI,MAAA,QAAA,GAAA;MAHC,eAAa,MAAA,MAAM,UAAM;MACzB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAA,QAAW,UAAU,KAAA,EAAS,CAAA;;;;IAIxEJ,YAQgBK,wBAAA,EARA,OAAOD,MAAA,QAAA,CAAQ,CAAC,U;KAC9B,SAAAE,cAME,CANFN,YAMEI,MAAA,cAAA,GAAA;MALC,eAAa,MAAA,MAAM,aAAS;MAC5B,KAAK;MACL,KAAK;MACL,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,cAAc,IAAG,EAAA,WAAc,aAAa,KAAA,EAAS,CAAA;;;;IAG/D,MAAA,MAAM,UAAtBN,UAAA,GAAAC,mBAaWS,UAAA,EAAA,KAAA,EAAA,GAAA,CAZTR,YAKEG,sBAAA;KAJC,eAAa,MAAA,MAAM;KACnB,OAAOC,MAAA,QAAA,CAAQ,CAAC;KAChB,QAAQ,OAAA;KACR,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAU,MAAK,CAAA;;;;;I,IAEpDJ,YAKEG,sBAAA;KAJC,eAAa,MAAA,MAAM;KACnB,OAAOC,MAAA,QAAA,CAAQ,CAAC;KAChB,QAAQ,OAAA;KACR,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAU,MAAK,CAAA"}
1
+ {"version":3,"file":"stat-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SourceField","_createBlock","FieldSelect","_unref","SettingsField","_withCtx","_createElementVNode","_Fragment","_createCommentVNode"],"sources":["../../src/widgets/stat-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouInput, DouInputNumber } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport FieldSelect from './field-select.vue'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { StatWidgetProps } from './types'\nimport { statPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardStatSettings' })\n\nconst model = defineModel<StatWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => statPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst fields = computed(() => fieldsOf(data.value))\nconst set = (patch: Partial<StatWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"view.source\"\n optional\n @update:model-value=\"(source) => set({ source })\"\n />\n <FieldSelect\n v-if=\"view.source\"\n :model-value=\"view.field\"\n :label=\"messages.value\"\n :fields=\"fields\"\n @update:model-value=\"(field) => set({ field: field as string | undefined })\"\n />\n <SettingsField v-else :label=\"messages.value\">\n <DouInputNumber\n :model-value=\"view.value ?? null\"\n :aria-label=\"messages.value\"\n @update:model-value=\"(value) => set({ value: value ?? undefined })\"\n />\n </SettingsField>\n <div class=\"dou-dashboard__field-row\">\n <SettingsField :label=\"messages.prefix\">\n <DouInput\n :model-value=\"view.prefix ?? ''\"\n :aria-label=\"messages.prefix\"\n @update:model-value=\"(prefix) => set({ prefix: prefix || undefined })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.suffix\">\n <DouInput\n :model-value=\"view.suffix ?? ''\"\n :aria-label=\"messages.suffix\"\n @update:model-value=\"(suffix) => set({ suffix: suffix || undefined })\"\n />\n </SettingsField>\n </div>\n <SettingsField :label=\"messages.precision\">\n <DouInputNumber\n :model-value=\"view.precision ?? null\"\n :min=\"0\"\n :max=\"6\"\n :aria-label=\"messages.precision\"\n @update:model-value=\"(precision) => set({ precision: precision ?? undefined })\"\n />\n </SettingsField>\n <template v-if=\"view.source\">\n <FieldSelect\n :model-value=\"view.trend\"\n :label=\"messages.trend\"\n :fields=\"fields\"\n @update:model-value=\"(trend) => set({ trend: trend as string | undefined })\"\n />\n <FieldSelect\n :model-value=\"view.delta\"\n :label=\"messages.delta\"\n :fields=\"fields\"\n @update:model-value=\"(delta) => set({ delta: delta as string | undefined })\"\n />\n </template>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAcA,MAAM,QAAQA,SAA4B,SAAA,YAAmB;EAE7D,MAAM,OAAO,eAAe,YAAY,MAAM,KAAgC,CAAC;EAC/E,MAAM,WAAW,qBAAqB;EACtC,MAAM,EAAE,SAAS,mBAAmB;EACpC,MAAM,SAAS,eAAe,SAAS,KAAK,KAAK,CAAC;EAClD,MAAM,OAAO,UAAqC,MAAM,QAAQ;GAAE,GAAG,MAAM;GAAO,GAAG;EAAM;;GAIzF,OAAAC,UAAA,GAAAC,mBA2DM,OA3DN,YA2DM;IA1DJC,YAIEC,sBAAA;KAHC,eAAa,KAAA,MAAK;KACnB,UAAA;KACC,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAG,OAAM,CAAA;;IAGvC,KAAA,MAAK,UADbH,UAAA,GAAAI,YAMEC,sBAAA;;KAJC,eAAa,KAAA,MAAK;KAClB,OAAOC,MAAA,QAAA,CAAQ,CAAC;KAChB,QAAQ,OAAA;KACR,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAU,MAAK,CAAA;;;;;I,OAEpDN,UAAA,GAAAI,YAMgBG,wBAAA;;KANO,OAAOD,MAAA,QAAA,CAAQ,CAAC;;KACrC,SAAAE,cAIE,CAJFN,YAIEI,MAAA,cAAA,GAAA;MAHC,eAAa,KAAA,MAAK,SAAK;MACvB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAA,OAAU,SAAS,KAAA,EAAS,CAAA;;;;IAGnEG,mBAeM,OAfN,YAeM,CAdJP,YAMgBK,wBAAA,EANA,OAAOD,MAAA,QAAA,CAAQ,CAAC,O;KAC9B,SAAAE,cAIE,CAJFN,YAIEI,MAAA,QAAA,GAAA;MAHC,eAAa,KAAA,MAAK,UAAM;MACxB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAA,QAAW,UAAU,KAAA,EAAS,CAAA;;;I,kBAGtEJ,YAMgBK,wBAAA,EANA,OAAOD,MAAA,QAAA,CAAQ,CAAC,O;KAC9B,SAAAE,cAIE,CAJFN,YAIEI,MAAA,QAAA,GAAA;MAHC,eAAa,KAAA,MAAK,UAAM;MACxB,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAA,QAAW,UAAU,KAAA,EAAS,CAAA;;;;IAIxEJ,YAQgBK,wBAAA,EARA,OAAOD,MAAA,QAAA,CAAQ,CAAC,U;KAC9B,SAAAE,cAME,CANFN,YAMEI,MAAA,cAAA,GAAA;MALC,eAAa,KAAA,MAAK,aAAS;MAC3B,KAAK;MACL,KAAK;MACL,cAAYA,MAAA,QAAA,CAAQ,CAAC;MACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,cAAc,IAAG,EAAA,WAAc,aAAa,KAAA,EAAS,CAAA;;;;IAG/D,KAAA,MAAK,UAArBN,UAAA,GAAAC,mBAaWS,UAAA,EAAA,KAAA,EAAA,GAAA,CAZTR,YAKEG,sBAAA;KAJC,eAAa,KAAA,MAAK;KAClB,OAAOC,MAAA,QAAA,CAAQ,CAAC;KAChB,QAAQ,OAAA;KACR,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAU,MAAK,CAAA;;;;;I,IAEpDJ,YAKEG,sBAAA;KAJC,eAAa,KAAA,MAAK;KAClB,OAAOC,MAAA,QAAA,CAAQ,CAAC;KAChB,QAAQ,OAAA;KACR,uBAAkB,OAAA,OAAA,OAAA,MAAG,UAAU,IAAG,EAAU,MAAK,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"stat.js","names":["_sfc_main"],"sources":["../../src/widgets/stat.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSparkline, DouStatistic } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport { valueAt } from './shared'\nimport type { StatWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardStatWidget' })\n\nconst { props, data, size } = useDashboardWidget<StatWidgetProps>()\nconst messages = useDashboardMessages()\n\nconst value = computed(() => {\n const { field, value: fixed } = props.value\n if (!field) return fixed ?? null\n const read = Number(valueAt(data.value, field))\n return Number.isFinite(read) ? read : null\n})\nconst delta = computed(() => {\n const read = props.value.delta ? Number(valueAt(data.value, props.value.delta)) : Number.NaN\n return Number.isFinite(read) ? read : undefined\n})\nconst deltaText = computed(() => {\n if (delta.value === undefined) return ''\n const percent = `${delta.value > 0 ? '+' : ''}${(delta.value * 100).toFixed(1)}%`\n return format(messages.value.deltaText, { value: percent })\n})\nconst points = computed(() => {\n const list = props.value.trend ? valueAt(data.value, props.value.trend) : undefined\n return Array.isArray(list) ? list.map(Number).filter(Number.isFinite) : []\n})\n/** The sparkline takes what the number leaves of the height, out to the card's edges. */\nconst sparkHeight = computed(() => Math.max(0, Math.floor(size.height.value - 56)))\n</script>\n\n<template>\n <div class=\"dou-dashboard-stat\">\n <DouStatistic\n :value=\"value\"\n :precision=\"props.precision\"\n :prefix=\"props.prefix\"\n :suffix=\"props.suffix\"\n :trend=\"delta === undefined || delta === 0 ? undefined : delta > 0 ? 'up' : 'down'\"\n >\n <template v-if=\"deltaText\" #footer>{{ deltaText }}</template>\n </DouStatistic>\n <div v-if=\"points.length > 1 && sparkHeight >= 24\" class=\"dou-dashboard-stat__spark\">\n <DouSparkline\n :data=\"points\"\n type=\"area\"\n smooth\n :width=\"size.width.value + 32\"\n :height=\"sparkHeight\"\n />\n </div>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"stat.js","names":["_sfc_main"],"sources":["../../src/widgets/stat.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSparkline, DouStatistic } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport { statPropsOf } from './read-props'\nimport { numberOf, valueAt } from './shared'\n\ndefineOptions({ name: 'DouDashboardStatWidget' })\n\nconst { props: raw, data, size } = useDashboardWidget()\nconst props = computed(() => statPropsOf(raw.value))\nconst messages = useDashboardMessages()\n\n// a fixed value and one read from the data follow the same rule: a number, or text that is one\nconst value = computed(() => {\n const { field, value: fixed } = props.value\n return (field ? numberOf(valueAt(data.value, field)) : fixed) ?? null\n})\nconst delta = computed(() =>\n props.value.delta ? numberOf(valueAt(data.value, props.value.delta)) : undefined,\n)\nconst deltaText = computed(() => {\n if (delta.value === undefined) return ''\n const percent = `${delta.value > 0 ? '+' : ''}${(delta.value * 100).toFixed(1)}%`\n return format(messages.value.deltaText, { value: percent })\n})\nconst points = computed(() => {\n const list = props.value.trend ? valueAt(data.value, props.value.trend) : undefined\n return Array.isArray(list) ? list.map(numberOf).filter((n): n is number => n !== undefined) : []\n})\n/** The sparkline takes what the number leaves of the height, out to the card's edges. */\nconst sparkHeight = computed(() => Math.max(0, Math.floor(size.height.value - 56)))\n</script>\n\n<template>\n <div class=\"dou-dashboard-stat\">\n <DouStatistic\n :value=\"value\"\n :precision=\"props.precision\"\n :prefix=\"props.prefix\"\n :suffix=\"props.suffix\"\n :trend=\"delta === undefined || delta === 0 ? undefined : delta > 0 ? 'up' : 'down'\"\n >\n <template v-if=\"deltaText\" #footer>{{ deltaText }}</template>\n </DouStatistic>\n <div v-if=\"points.length > 1 && sparkHeight >= 24\" class=\"dou-dashboard-stat__spark\">\n <DouSparkline\n :data=\"points\"\n type=\"area\"\n smooth\n :width=\"size.width.value + 32\"\n :height=\"sparkHeight\"\n />\n </div>\n </div>\n</template>\n"],"mappings":""}
@@ -1,6 +1,7 @@
1
1
  import { format, useDashboardMessages } from "../locale.js";
2
2
  import { useDashboardWidget } from "../widget/context.js";
3
- import { valueAt } from "./shared.js";
3
+ import { numberOf, valueAt } from "./shared.js";
4
+ import { statPropsOf } from "./read-props.js";
4
5
  import { DouSparkline, DouStatistic } from "dou-ui";
5
6
  import { computed, createCommentVNode, createElementBlock, createSlots, createTextVNode, createVNode, defineComponent, openBlock, toDisplayString, unref, withCtx } from "vue";
6
7
  // src/widgets/stat.vue?vue&type=script&setup=true&lang.ts
@@ -13,18 +14,14 @@ var stat_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
13
14
  name: "DouDashboardStatWidget",
14
15
  __name: "stat",
15
16
  setup(__props) {
16
- const { props, data, size } = useDashboardWidget();
17
+ const { props: raw, data, size } = useDashboardWidget();
18
+ const props = computed(() => statPropsOf(raw.value));
17
19
  const messages = useDashboardMessages();
18
20
  const value = computed(() => {
19
21
  const { field, value: fixed } = props.value;
20
- if (!field) return fixed ?? null;
21
- const read = Number(valueAt(data.value, field));
22
- return Number.isFinite(read) ? read : null;
23
- });
24
- const delta = computed(() => {
25
- const read = props.value.delta ? Number(valueAt(data.value, props.value.delta)) : NaN;
26
- return Number.isFinite(read) ? read : void 0;
22
+ return (field ? numberOf(valueAt(data.value, field)) : fixed) ?? null;
27
23
  });
24
+ const delta = computed(() => props.value.delta ? numberOf(valueAt(data.value, props.value.delta)) : void 0);
28
25
  const deltaText = computed(() => {
29
26
  if (delta.value === void 0) return "";
30
27
  const percent = `${delta.value > 0 ? "+" : ""}${(delta.value * 100).toFixed(1)}%`;
@@ -32,16 +29,16 @@ var stat_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
32
29
  });
33
30
  const points = computed(() => {
34
31
  const list = props.value.trend ? valueAt(data.value, props.value.trend) : void 0;
35
- return Array.isArray(list) ? list.map(Number).filter(Number.isFinite) : [];
32
+ return Array.isArray(list) ? list.map(numberOf).filter((n) => n !== void 0) : [];
36
33
  });
37
34
  /** The sparkline takes what the number leaves of the height, out to the card's edges. */
38
35
  const sparkHeight = computed(() => Math.max(0, Math.floor(size.height.value - 56)));
39
36
  return (_ctx, _cache) => {
40
37
  return openBlock(), createElementBlock("div", _hoisted_1, [createVNode(unref(DouStatistic), {
41
38
  value: value.value,
42
- precision: unref(props).precision,
43
- prefix: unref(props).prefix,
44
- suffix: unref(props).suffix,
39
+ precision: props.value.precision,
40
+ prefix: props.value.prefix,
41
+ suffix: props.value.suffix,
45
42
  trend: delta.value === void 0 || delta.value === 0 ? void 0 : delta.value > 0 ? "up" : "down"
46
43
  }, createSlots({ _: 2 }, [deltaText.value ? {
47
44
  name: "footer",
@@ -1 +1 @@
1
- {"version":3,"file":"stat.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createVNode","_unref","_createSlots","_withCtx","_createTextVNode","_toDisplayString","_createCommentVNode"],"sources":["../../src/widgets/stat.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSparkline, DouStatistic } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport { valueAt } from './shared'\nimport type { StatWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardStatWidget' })\n\nconst { props, data, size } = useDashboardWidget<StatWidgetProps>()\nconst messages = useDashboardMessages()\n\nconst value = computed(() => {\n const { field, value: fixed } = props.value\n if (!field) return fixed ?? null\n const read = Number(valueAt(data.value, field))\n return Number.isFinite(read) ? read : null\n})\nconst delta = computed(() => {\n const read = props.value.delta ? Number(valueAt(data.value, props.value.delta)) : Number.NaN\n return Number.isFinite(read) ? read : undefined\n})\nconst deltaText = computed(() => {\n if (delta.value === undefined) return ''\n const percent = `${delta.value > 0 ? '+' : ''}${(delta.value * 100).toFixed(1)}%`\n return format(messages.value.deltaText, { value: percent })\n})\nconst points = computed(() => {\n const list = props.value.trend ? valueAt(data.value, props.value.trend) : undefined\n return Array.isArray(list) ? list.map(Number).filter(Number.isFinite) : []\n})\n/** The sparkline takes what the number leaves of the height, out to the card's edges. */\nconst sparkHeight = computed(() => Math.max(0, Math.floor(size.height.value - 56)))\n</script>\n\n<template>\n <div class=\"dou-dashboard-stat\">\n <DouStatistic\n :value=\"value\"\n :precision=\"props.precision\"\n :prefix=\"props.prefix\"\n :suffix=\"props.suffix\"\n :trend=\"delta === undefined || delta === 0 ? undefined : delta > 0 ? 'up' : 'down'\"\n >\n <template v-if=\"deltaText\" #footer>{{ deltaText }}</template>\n </DouStatistic>\n <div v-if=\"points.length > 1 && sparkHeight >= 24\" class=\"dou-dashboard-stat__spark\">\n <DouSparkline\n :data=\"points\"\n type=\"area\"\n smooth\n :width=\"size.width.value + 32\"\n :height=\"sparkHeight\"\n />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;EAUA,MAAM,EAAE,OAAO,MAAM,SAAS,mBAAoC;EAClE,MAAM,WAAW,qBAAqB;EAEtC,MAAM,QAAQ,eAAe;GAC3B,MAAM,EAAE,OAAO,OAAO,UAAU,MAAM;GACtC,IAAI,CAAC,OAAO,OAAO,SAAS;GAC5B,MAAM,OAAO,OAAO,QAAQ,KAAK,OAAO,KAAK,CAAC;GAC9C,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO;EACxC,CAAC;EACD,MAAM,QAAQ,eAAe;GAC3B,MAAM,OAAO,MAAM,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,MAAM,MAAM,KAAK,CAAC,IAAI;GAClF,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO,KAAA;EACxC,CAAC;EACD,MAAM,YAAY,eAAe;GAC/B,IAAI,MAAM,UAAU,KAAA,GAAW,OAAO;GACtC,MAAM,UAAU,GAAG,MAAM,QAAQ,IAAI,MAAM,MAAM,MAAM,QAAQ,IAAA,CAAK,QAAQ,CAAC,EAAE;GAC/E,OAAO,OAAO,SAAS,MAAM,WAAW,EAAE,OAAO,QAAQ,CAAC;EAC5D,CAAC;EACD,MAAM,SAAS,eAAe;GAC5B,MAAM,OAAO,MAAM,MAAM,QAAQ,QAAQ,KAAK,OAAO,MAAM,MAAM,KAAK,IAAI,KAAA;GAC1E,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,MAAM,CAAC,CAAC,OAAO,OAAO,QAAQ,IAAI,CAAC;EAC3E,CAAC;;EAED,MAAM,cAAc,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,OAAO,QAAQ,EAAE,CAAC,CAAC;;GAIhF,OAAAA,UAAA,GAAAC,mBAmBM,OAnBN,YAmBM,CAlBJC,YAQeC,MAAA,YAAA,GAAA;IAPZ,OAAO,MAAA;IACP,WAAWA,MAAA,KAAA,CAAK,CAAC;IACjB,QAAQA,MAAA,KAAA,CAAK,CAAC;IACd,QAAQA,MAAA,KAAA,CAAK,CAAC;IACd,OAAO,MAAA,UAAU,KAAA,KAAa,MAAA,UAAK,IAAS,KAAA,IAAY,MAAA,QAAK,IAAA,OAAA;G,0BAE9C,UAAA,Q;IAAY,MAAA;IAAO,IAAAE,cAAe,CAAZC,gBAAAC,gBAAA,UAAA,KAAS,GAAA,CAAA,C;;;;;;;;G,IAEtC,OAAA,MAAO,SAAM,KAAQ,YAAA,SAAW,MAA3CP,UAAA,GAAAC,mBAQM,OARN,YAQM,CAPJC,YAMEC,MAAA,YAAA,GAAA;IALC,MAAM,OAAA;IACP,MAAK;IACL,QAAA;IACC,OAAOA,MAAA,IAAA,CAAI,CAAC,MAAM,QAAK;IACvB,QAAQ,YAAA"}
1
+ {"version":3,"file":"stat.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createVNode","_unref","_createSlots","_withCtx","_createTextVNode","_toDisplayString","_createCommentVNode"],"sources":["../../src/widgets/stat.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSparkline, DouStatistic } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport { statPropsOf } from './read-props'\nimport { numberOf, valueAt } from './shared'\n\ndefineOptions({ name: 'DouDashboardStatWidget' })\n\nconst { props: raw, data, size } = useDashboardWidget()\nconst props = computed(() => statPropsOf(raw.value))\nconst messages = useDashboardMessages()\n\n// a fixed value and one read from the data follow the same rule: a number, or text that is one\nconst value = computed(() => {\n const { field, value: fixed } = props.value\n return (field ? numberOf(valueAt(data.value, field)) : fixed) ?? null\n})\nconst delta = computed(() =>\n props.value.delta ? numberOf(valueAt(data.value, props.value.delta)) : undefined,\n)\nconst deltaText = computed(() => {\n if (delta.value === undefined) return ''\n const percent = `${delta.value > 0 ? '+' : ''}${(delta.value * 100).toFixed(1)}%`\n return format(messages.value.deltaText, { value: percent })\n})\nconst points = computed(() => {\n const list = props.value.trend ? valueAt(data.value, props.value.trend) : undefined\n return Array.isArray(list) ? list.map(numberOf).filter((n): n is number => n !== undefined) : []\n})\n/** The sparkline takes what the number leaves of the height, out to the card's edges. */\nconst sparkHeight = computed(() => Math.max(0, Math.floor(size.height.value - 56)))\n</script>\n\n<template>\n <div class=\"dou-dashboard-stat\">\n <DouStatistic\n :value=\"value\"\n :precision=\"props.precision\"\n :prefix=\"props.prefix\"\n :suffix=\"props.suffix\"\n :trend=\"delta === undefined || delta === 0 ? undefined : delta > 0 ? 'up' : 'down'\"\n >\n <template v-if=\"deltaText\" #footer>{{ deltaText }}</template>\n </DouStatistic>\n <div v-if=\"points.length > 1 && sparkHeight >= 24\" class=\"dou-dashboard-stat__spark\">\n <DouSparkline\n :data=\"points\"\n type=\"area\"\n smooth\n :width=\"size.width.value + 32\"\n :height=\"sparkHeight\"\n />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;EAUA,MAAM,EAAE,OAAO,KAAK,MAAM,SAAS,mBAAmB;EACtD,MAAM,QAAQ,eAAe,YAAY,IAAI,KAAK,CAAC;EACnD,MAAM,WAAW,qBAAqB;EAGtC,MAAM,QAAQ,eAAe;GAC3B,MAAM,EAAE,OAAO,OAAO,UAAU,MAAM;GACtC,QAAQ,QAAQ,SAAS,QAAQ,KAAK,OAAO,KAAK,CAAC,IAAI,UAAU;EACnE,CAAC;EACD,MAAM,QAAQ,eACZ,MAAM,MAAM,QAAQ,SAAS,QAAQ,KAAK,OAAO,MAAM,MAAM,KAAK,CAAC,IAAI,KAAA,CACzE;EACA,MAAM,YAAY,eAAe;GAC/B,IAAI,MAAM,UAAU,KAAA,GAAW,OAAO;GACtC,MAAM,UAAU,GAAG,MAAM,QAAQ,IAAI,MAAM,MAAM,MAAM,QAAQ,IAAA,CAAK,QAAQ,CAAC,EAAE;GAC/E,OAAO,OAAO,SAAS,MAAM,WAAW,EAAE,OAAO,QAAQ,CAAC;EAC5D,CAAC;EACD,MAAM,SAAS,eAAe;GAC5B,MAAM,OAAO,MAAM,MAAM,QAAQ,QAAQ,KAAK,OAAO,MAAM,MAAM,KAAK,IAAI,KAAA;GAC1E,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,QAAQ,CAAC,CAAC,QAAQ,MAAmB,MAAM,KAAA,CAAS,IAAI,CAAC;EACjG,CAAC;;EAED,MAAM,cAAc,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,OAAO,QAAQ,EAAE,CAAC,CAAC;;GAIhF,OAAAA,UAAA,GAAAC,mBAmBM,OAnBN,YAmBM,CAlBJC,YAQeC,MAAA,YAAA,GAAA;IAPZ,OAAO,MAAA;IACP,WAAW,MAAA,MAAM;IACjB,QAAQ,MAAA,MAAM;IACd,QAAQ,MAAA,MAAM;IACd,OAAO,MAAA,UAAU,KAAA,KAAa,MAAA,UAAK,IAAS,KAAA,IAAY,MAAA,QAAK,IAAA,OAAA;G,0BAE9C,UAAA,Q;IAAY,MAAA;IAAO,IAAAE,cAAe,CAAZC,gBAAAC,gBAAA,UAAA,KAAS,GAAA,CAAA,C;;;;;;;;G,IAEtC,OAAA,MAAO,SAAM,KAAQ,YAAA,SAAW,MAA3CP,UAAA,GAAAC,mBAQM,OARN,YAQM,CAPJC,YAMEC,MAAA,YAAA,GAAA;IALC,MAAM,OAAA;IACP,MAAK;IACL,QAAA;IACC,OAAOA,MAAA,IAAA,CAAI,CAAC,MAAM,QAAK;IACvB,QAAQ,YAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"table-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/table-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouCheckbox, DouInput } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf, rowsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableSettings' })\n\nconst model = defineModel<TableWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\n\n/** Every field of the rows, those shown first in their order. */\nconst fields = computed(() => {\n const all = fieldsOf(rowsOf(data.value, model.value.path))\n const shown = model.value.columns?.map((column) => column.key) ?? all\n return [...shown, ...all.filter((key) => !shown.includes(key))]\n})\nconst columns = computed<TableWidgetColumn[]>(\n () =>\n model.value.columns ?? fieldsOf(rowsOf(data.value, model.value.path)).map((key) => ({ key })),\n)\nconst columnOf = (key: string) => columns.value.find((column) => column.key === key)\n\nfunction toggle(key: string, on: boolean) {\n const next = on\n ? [...columns.value, { key }]\n : columns.value.filter((column) => column.key !== key)\n model.value = { ...model.value, columns: next }\n}\n\nfunction retitle(key: string, title: string) {\n const next = columns.value.map((column) =>\n column.key === key ? { key, ...(title ? { title } : {}) } : column,\n )\n model.value = { ...model.value, columns: next }\n}\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"model.source\"\n @update:model-value=\"(source) => (model = { ...model, source })\"\n />\n <SettingsField v-if=\"fields.length\" :label=\"messages.columns\">\n <div class=\"dou-dashboard__columns\">\n <div v-for=\"key in fields\" :key=\"key\" class=\"dou-dashboard__column\">\n <DouCheckbox\n :model-value=\"!!columnOf(key)\"\n @update:model-value=\"(on) => toggle(key, !!on)\"\n >\n {{ key }}\n </DouCheckbox>\n <DouInput\n v-if=\"columnOf(key)\"\n size=\"sm\"\n :model-value=\"columnOf(key)?.title ?? ''\"\n :placeholder=\"key\"\n :aria-label=\"format(messages.columnTitle, { field: key })\"\n @update:model-value=\"(title) => retitle(key, title)\"\n />\n </div>\n </div>\n </SettingsField>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"table-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/table-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouCheckbox, DouInput } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf, rowsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\nimport { tablePropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardTableSettings' })\n\nconst model = defineModel<TableWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => tablePropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\n\n/** Every field of the rows, those shown first in their order. */\nconst fields = computed(() => {\n const all = fieldsOf(rowsOf(data.value, view.value.path))\n const shown = view.value.columns?.map((column) => column.key) ?? all\n return [...shown, ...all.filter((key) => !shown.includes(key))]\n})\nconst columns = computed<TableWidgetColumn[]>(\n () => view.value.columns ?? fieldsOf(rowsOf(data.value, view.value.path)).map((key) => ({ key })),\n)\nconst columnOf = (key: string) => columns.value.find((column) => column.key === key)\n\nfunction toggle(key: string, on: boolean) {\n const next = on\n ? [...columns.value, { key }]\n : columns.value.filter((column) => column.key !== key)\n model.value = { ...model.value, columns: next }\n}\n\nfunction retitle(key: string, title: string) {\n const next = columns.value.map((column) =>\n column.key === key ? { key, ...(title ? { title } : {}) } : column,\n )\n model.value = { ...model.value, columns: next }\n}\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"view.source\"\n @update:model-value=\"(source) => (model = { ...model, source })\"\n />\n <SettingsField v-if=\"fields.length\" :label=\"messages.columns\">\n <div class=\"dou-dashboard__columns\">\n <div v-for=\"key in fields\" :key=\"key\" class=\"dou-dashboard__column\">\n <DouCheckbox\n :model-value=\"!!columnOf(key)\"\n @update:model-value=\"(on) => toggle(key, !!on)\"\n >\n {{ key }}\n </DouCheckbox>\n <DouInput\n v-if=\"columnOf(key)\"\n size=\"sm\"\n :model-value=\"columnOf(key)?.title ?? ''\"\n :placeholder=\"key\"\n :aria-label=\"format(messages.columnTitle, { field: key })\"\n @update:model-value=\"(title) => retitle(key, title)\"\n />\n </div>\n </div>\n </SettingsField>\n </div>\n</template>\n"],"mappings":""}
@@ -1,6 +1,7 @@
1
1
  import { format, useDashboardMessages } from "../locale.js";
2
2
  import { useDashboardWidget } from "../widget/context.js";
3
3
  import { fieldsOf, rowsOf } from "./shared.js";
4
+ import { tablePropsOf } from "./read-props.js";
4
5
  import settings_field_default from "./settings-field.js";
5
6
  import source_field_default from "./source-field.js";
6
7
  import { DouCheckbox, DouInput } from "dou-ui";
@@ -18,15 +19,16 @@ var table_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
18
19
  emits: ["update:modelValue"],
19
20
  setup(__props) {
20
21
  const model = useModel(__props, "modelValue");
22
+ const view = computed(() => tablePropsOf(model.value));
21
23
  const messages = useDashboardMessages();
22
24
  const { data } = useDashboardWidget();
23
25
  /** Every field of the rows, those shown first in their order. */
24
26
  const fields = computed(() => {
25
- const all = fieldsOf(rowsOf(data.value, model.value.path));
26
- const shown = model.value.columns?.map((column) => column.key) ?? all;
27
+ const all = fieldsOf(rowsOf(data.value, view.value.path));
28
+ const shown = view.value.columns?.map((column) => column.key) ?? all;
27
29
  return [...shown, ...all.filter((key) => !shown.includes(key))];
28
30
  });
29
- const columns = computed(() => model.value.columns ?? fieldsOf(rowsOf(data.value, model.value.path)).map((key) => ({ key })));
31
+ const columns = computed(() => view.value.columns ?? fieldsOf(rowsOf(data.value, view.value.path)).map((key) => ({ key })));
30
32
  const columnOf = (key) => columns.value.find((column) => column.key === key);
31
33
  function toggle(key, on) {
32
34
  const next = on ? [...columns.value, { key }] : columns.value.filter((column) => column.key !== key);
@@ -47,7 +49,7 @@ var table_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
47
49
  }
48
50
  return (_ctx, _cache) => {
49
51
  return openBlock(), createElementBlock("div", _hoisted_1, [createVNode(source_field_default, {
50
- "model-value": model.value.source,
52
+ "model-value": view.value.source,
51
53
  "onUpdate:modelValue": _cache[0] || (_cache[0] = (source) => model.value = {
52
54
  ...model.value,
53
55
  source
@@ -1 +1 @@
1
- {"version":3,"file":"table-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SourceField","_createBlock","SettingsField","_unref","_withCtx","_createElementVNode","_Fragment","_renderList","_createTextVNode","_toDisplayString","_createCommentVNode"],"sources":["../../src/widgets/table-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouCheckbox, DouInput } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf, rowsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableSettings' })\n\nconst model = defineModel<TableWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\n\n/** Every field of the rows, those shown first in their order. */\nconst fields = computed(() => {\n const all = fieldsOf(rowsOf(data.value, model.value.path))\n const shown = model.value.columns?.map((column) => column.key) ?? all\n return [...shown, ...all.filter((key) => !shown.includes(key))]\n})\nconst columns = computed<TableWidgetColumn[]>(\n () =>\n model.value.columns ?? fieldsOf(rowsOf(data.value, model.value.path)).map((key) => ({ key })),\n)\nconst columnOf = (key: string) => columns.value.find((column) => column.key === key)\n\nfunction toggle(key: string, on: boolean) {\n const next = on\n ? [...columns.value, { key }]\n : columns.value.filter((column) => column.key !== key)\n model.value = { ...model.value, columns: next }\n}\n\nfunction retitle(key: string, title: string) {\n const next = columns.value.map((column) =>\n column.key === key ? { key, ...(title ? { title } : {}) } : column,\n )\n model.value = { ...model.value, columns: next }\n}\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"model.source\"\n @update:model-value=\"(source) => (model = { ...model, source })\"\n />\n <SettingsField v-if=\"fields.length\" :label=\"messages.columns\">\n <div class=\"dou-dashboard__columns\">\n <div v-for=\"key in fields\" :key=\"key\" class=\"dou-dashboard__column\">\n <DouCheckbox\n :model-value=\"!!columnOf(key)\"\n @update:model-value=\"(on) => toggle(key, !!on)\"\n >\n {{ key }}\n </DouCheckbox>\n <DouInput\n v-if=\"columnOf(key)\"\n size=\"sm\"\n :model-value=\"columnOf(key)?.title ?? ''\"\n :placeholder=\"key\"\n :aria-label=\"format(messages.columnTitle, { field: key })\"\n @update:model-value=\"(title) => retitle(key, title)\"\n />\n </div>\n </div>\n </SettingsField>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAYA,MAAM,QAAQA,SAA6B,SAAA,YAAmB;EAC9D,MAAM,WAAW,qBAAqB;EACtC,MAAM,EAAE,SAAS,mBAAmB;;EAGpC,MAAM,SAAS,eAAe;GAC5B,MAAM,MAAM,SAAS,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;GACzD,MAAM,QAAQ,MAAM,MAAM,SAAS,KAAK,WAAW,OAAO,GAAG,KAAK;GAClE,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,QAAQ,QAAQ,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;EAChE,CAAC;EACD,MAAM,UAAU,eAEZ,MAAM,MAAM,WAAW,SAAS,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,IAAI,EAAE,CAChG;EACA,MAAM,YAAY,QAAgB,QAAQ,MAAM,MAAM,WAAW,OAAO,QAAQ,GAAG;EAEnF,SAAS,OAAO,KAAa,IAAa;GACxC,MAAM,OAAO,KACT,CAAC,GAAG,QAAQ,OAAO,EAAE,IAAI,CAAC,IAC1B,QAAQ,MAAM,QAAQ,WAAW,OAAO,QAAQ,GAAG;GACvD,MAAM,QAAQ;IAAE,GAAG,MAAM;IAAO,SAAS;GAAK;EAChD;EAEA,SAAS,QAAQ,KAAa,OAAe;GAC3C,MAAM,OAAO,QAAQ,MAAM,KAAK,WAC9B,OAAO,QAAQ,MAAM;IAAE;IAAK,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAAG,IAAI,MAC9D;GACA,MAAM,QAAQ;IAAE,GAAG,MAAM;IAAO,SAAS;GAAK;EAChD;;GAIE,OAAAC,UAAA,GAAAC,mBAyBM,OAzBN,YAyBM,CAxBJC,YAGEC,sBAAA;IAFC,eAAa,MAAA,MAAM;IACnB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAY,MAAA,QAAK;KAAA,GAAQ,MAAA;KAAO;IAAM;G,8BAEzC,OAAA,MAAO,UAA5BH,UAAA,GAAAI,YAmBgBC,wBAAA;;IAnBqB,OAAOC,MAAA,QAAA,CAAQ,CAAC;;IACnD,SAAAC,cAiBM,CAjBNC,mBAiBM,OAjBN,YAiBM,EAhBJR,UAAA,IAAA,GAAAC,mBAeMQ,UAAA,MAAAC,WAfa,OAAA,QAAP,QAAG;KAAf,OAAAV,UAAA,GAAAC,mBAeM,OAAA;MAf2B;MAAK,OAAM;K,IAC1CC,YAKcI,MAAA,WAAA,GAAA;MAJX,eAAW,CAAA,CAAI,SAAS,GAAG;MAC3B,wBAAqB,OAAO,OAAO,KAAG,CAAA,CAAI,EAAE;;MAE7C,SAAAC,cAAS,CAANI,gBAAAC,gBAAA,GAAG,GAAA,CAAA,C;;K,kDAGA,SAAS,GAAG,KADpBZ,UAAA,GAAAI,YAOEE,MAAA,QAAA,GAAA;;MALA,MAAK;MACJ,eAAa,SAAS,GAAG,CAAA,EAAG,SAAK;MACjC,aAAa;MACb,cAAYA,MAAA,MAAA,CAAM,CAACA,MAAA,QAAA,CAAQ,CAAC,aAAW,EAAA,OAAW,IAAG,CAAA;MACrD,wBAAqB,UAAU,QAAQ,KAAK,KAAK"}
1
+ {"version":3,"file":"table-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SourceField","_createBlock","SettingsField","_unref","_withCtx","_createElementVNode","_Fragment","_renderList","_createTextVNode","_toDisplayString","_createCommentVNode"],"sources":["../../src/widgets/table-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouCheckbox, DouInput } from 'dou-ui'\nimport { computed } from 'vue'\nimport { format, useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from './settings-field.vue'\nimport { fieldsOf, rowsOf } from './shared'\nimport SourceField from './source-field.vue'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\nimport { tablePropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardTableSettings' })\n\nconst model = defineModel<TableWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => tablePropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\n\n/** Every field of the rows, those shown first in their order. */\nconst fields = computed(() => {\n const all = fieldsOf(rowsOf(data.value, view.value.path))\n const shown = view.value.columns?.map((column) => column.key) ?? all\n return [...shown, ...all.filter((key) => !shown.includes(key))]\n})\nconst columns = computed<TableWidgetColumn[]>(\n () => view.value.columns ?? fieldsOf(rowsOf(data.value, view.value.path)).map((key) => ({ key })),\n)\nconst columnOf = (key: string) => columns.value.find((column) => column.key === key)\n\nfunction toggle(key: string, on: boolean) {\n const next = on\n ? [...columns.value, { key }]\n : columns.value.filter((column) => column.key !== key)\n model.value = { ...model.value, columns: next }\n}\n\nfunction retitle(key: string, title: string) {\n const next = columns.value.map((column) =>\n column.key === key ? { key, ...(title ? { title } : {}) } : column,\n )\n model.value = { ...model.value, columns: next }\n}\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField\n :model-value=\"view.source\"\n @update:model-value=\"(source) => (model = { ...model, source })\"\n />\n <SettingsField v-if=\"fields.length\" :label=\"messages.columns\">\n <div class=\"dou-dashboard__columns\">\n <div v-for=\"key in fields\" :key=\"key\" class=\"dou-dashboard__column\">\n <DouCheckbox\n :model-value=\"!!columnOf(key)\"\n @update:model-value=\"(on) => toggle(key, !!on)\"\n >\n {{ key }}\n </DouCheckbox>\n <DouInput\n v-if=\"columnOf(key)\"\n size=\"sm\"\n :model-value=\"columnOf(key)?.title ?? ''\"\n :placeholder=\"key\"\n :aria-label=\"format(messages.columnTitle, { field: key })\"\n @update:model-value=\"(title) => retitle(key, title)\"\n />\n </div>\n </div>\n </SettingsField>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAaA,MAAM,QAAQA,SAA6B,SAAA,YAAmB;EAE9D,MAAM,OAAO,eAAe,aAAa,MAAM,KAAgC,CAAC;EAChF,MAAM,WAAW,qBAAqB;EACtC,MAAM,EAAE,SAAS,mBAAmB;;EAGpC,MAAM,SAAS,eAAe;GAC5B,MAAM,MAAM,SAAS,OAAO,KAAK,OAAO,KAAK,MAAM,IAAI,CAAC;GACxD,MAAM,QAAQ,KAAK,MAAM,SAAS,KAAK,WAAW,OAAO,GAAG,KAAK;GACjE,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,QAAQ,QAAQ,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;EAChE,CAAC;EACD,MAAM,UAAU,eACR,KAAK,MAAM,WAAW,SAAS,OAAO,KAAK,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,IAAI,EAAE,CAClG;EACA,MAAM,YAAY,QAAgB,QAAQ,MAAM,MAAM,WAAW,OAAO,QAAQ,GAAG;EAEnF,SAAS,OAAO,KAAa,IAAa;GACxC,MAAM,OAAO,KACT,CAAC,GAAG,QAAQ,OAAO,EAAE,IAAI,CAAC,IAC1B,QAAQ,MAAM,QAAQ,WAAW,OAAO,QAAQ,GAAG;GACvD,MAAM,QAAQ;IAAE,GAAG,MAAM;IAAO,SAAS;GAAK;EAChD;EAEA,SAAS,QAAQ,KAAa,OAAe;GAC3C,MAAM,OAAO,QAAQ,MAAM,KAAK,WAC9B,OAAO,QAAQ,MAAM;IAAE;IAAK,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAAG,IAAI,MAC9D;GACA,MAAM,QAAQ;IAAE,GAAG,MAAM;IAAO,SAAS;GAAK;EAChD;;GAIE,OAAAC,UAAA,GAAAC,mBAyBM,OAzBN,YAyBM,CAxBJC,YAGEC,sBAAA;IAFC,eAAa,KAAA,MAAK;IAClB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAY,MAAA,QAAK;KAAA,GAAQ,MAAA;KAAO;IAAM;G,8BAEzC,OAAA,MAAO,UAA5BH,UAAA,GAAAI,YAmBgBC,wBAAA;;IAnBqB,OAAOC,MAAA,QAAA,CAAQ,CAAC;;IACnD,SAAAC,cAiBM,CAjBNC,mBAiBM,OAjBN,YAiBM,EAhBJR,UAAA,IAAA,GAAAC,mBAeMQ,UAAA,MAAAC,WAfa,OAAA,QAAP,QAAG;KAAf,OAAAV,UAAA,GAAAC,mBAeM,OAAA;MAf2B;MAAK,OAAM;K,IAC1CC,YAKcI,MAAA,WAAA,GAAA;MAJX,eAAW,CAAA,CAAI,SAAS,GAAG;MAC3B,wBAAqB,OAAO,OAAO,KAAG,CAAA,CAAI,EAAE;;MAE7C,SAAAC,cAAS,CAANI,gBAAAC,gBAAA,GAAG,GAAA,CAAA,C;;K,kDAGA,SAAS,GAAG,KADpBZ,UAAA,GAAAI,YAOEE,MAAA,QAAA,GAAA;;MALA,MAAK;MACJ,eAAa,SAAS,GAAG,CAAA,EAAG,SAAK;MACjC,aAAa;MACb,cAAYA,MAAA,MAAA,CAAM,CAACA,MAAA,QAAA,CAAQ,CAAC,aAAW,EAAA,OAAW,IAAG,CAAA;MACrD,wBAAqB,UAAU,QAAQ,KAAK,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","names":["_sfc_main"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props, data, size, setWorkbook } = useDashboardWidget<TableWidgetProps>()\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :bordered=\"false\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"table.js","names":["_sfc_main"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { tablePropsOf } from './read-props'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props: raw, data, size, setWorkbook } = useDashboardWidget()\nconst props = computed(() => tablePropsOf(raw.value))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :bordered=\"false\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":""}
@@ -1,5 +1,6 @@
1
1
  import { useDashboardWidget } from "../widget/context.js";
2
2
  import { fieldsOf, rowsOf, rowsToWorkbook } from "./shared.js";
3
+ import { tablePropsOf } from "./read-props.js";
3
4
  import { DouTable } from "dou-ui";
4
5
  import { computed, createBlock, defineComponent, onMounted, openBlock, ref, unref } from "vue";
5
6
  // src/widgets/table.vue?vue&type=script&setup=true&lang.ts
@@ -7,7 +8,8 @@ var table_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
7
8
  name: "DouDashboardTableWidget",
8
9
  __name: "table",
9
10
  setup(__props) {
10
- const { props, data, size, setWorkbook } = useDashboardWidget();
11
+ const { props: raw, data, size, setWorkbook } = useDashboardWidget();
12
+ const props = computed(() => tablePropsOf(raw.value));
11
13
  const rows = computed(() => rowsOf(data.value, props.value.path));
12
14
  /** Each row's key: its `rowKey` field, or its place in the list. */
13
15
  const keys = computed(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"table.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn, TableWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props, data, size, setWorkbook } = useDashboardWidget<TableWidgetProps>()\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :bordered=\"false\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":";;;;;;;;;EAUA,MAAM,EAAE,OAAO,MAAM,MAAM,gBAAgB,mBAAqC;EAChF,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;;EAEhE,MAAM,OAAO,eAAe;GAC1B,MAAM,sBAAM,IAAI,QAAiC;GACjD,MAAM,QAAQ,MAAM,MAAM;GAC1B,KAAK,MAAM,SAAS,KAAK,UAAU,IAAI,IAAI,KAAK,QAAS,IAAI,SAA6B,KAAK,CAAC;GAChG,OAAO;EACT,CAAC;EACD,MAAM,UAAU,QAAiC,KAAK,MAAM,IAAI,GAAG,KAAK;EACxE,MAAM,SAAS,IAAI,KAAK,aAAa;;EAErC,MAAM,OAAO,IAAsB;EACnC,MAAM,OAAO,IAAI,EAAE;EACnB,gBAAgB;GACd,MAAM,OAAO,KAAK,OAAO,IAAI,cAAc,QAAQ;GACnD,IAAI,MAAM,KAAK,QAAQ,iBAAiB,IAAI,CAAC,CAAC;EAChD,CAAC;EACD,IAAI;;EAEJ,SAAS,UAAU,MAAc;GAC/B,YACE,OAAO,aAAa,cAAc,OAAO,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI;GAC3F,IAAI,WAAW,KAAK,OAAO;IACzB,QAAQ,OAAO,KAAK;IACpB,OAAO,QAAQ,YAAY,IAAI,CAAC,CAAC;GACnC;GACA,IAAI,QAAQ;GACZ,KAAK,MAAM,QAAQ,MAAM,SAAS,KAAK,WAAW,CAAC,IAAI,QAAS,KAAK;GACrE,OAAO;EACT;;EAEA,SAAS,WAAW,OAAe,OAAkB;GACnD,IAAI,SAAS,UAAU,KAAK;GAC5B,KAAK,MAAM,QAAQ,OAAO,SAAS,KAAK,IAAI,QAAQ,UAAU,OAAO,QAAQ,EAAE,CAAC,CAAC;GACjF,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,EAAE;EAC7C;EACA,MAAM,UAAU,eAA8B;GAC5C,MAAM,QAAQ,KAAK,MAAM;GAGzB,QADE,MAAM,MAAM,WAAW,SAAS,KAAK,KAAK,CAAC,CAAC,KAAK,SAAS,EAAE,IAAI,EAAE,EAAA,CACxD,KAAK,EAAE,KAAK,YAAY;IAClC,MAAM,UAAU,OAAO,QAAQ,SAAS;IAExC,MAAM,QAAQ,WACT,QACC,OAAO,IAAI,SAAS,WAAW,OAAO,OAAO,IAAI,IAAc,IAAI,IAAI,OACzE,KAAA;IACJ,MAAM,SAAS,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,QAAS,QAAQ,MAAM,GAAG,IAAI,IAAI,IAAK;IACnF,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM;IAC7C,OAAO;KACL;KACA,OAAO,SAAS;KAChB,OAAO,UAAU,QAAQ,KAAA;KACzB,UAAU;KAEV,OAAO;KACP,UAAU;KACV;IACF;GACF,CAAC;EACH,CAAC;EAED,kBACE,eACE,IACA,QAAQ,MAAM,KAAK,YAAY;GAC7B,KAAK,OAAO;GACZ,OAAO,OAAO,OAAO,KAAK;GAC1B,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;EAC3D,EAAE,GACF,KAAK,KACP,CACF;;GAIE,OAAAA,UAAA,GAAAC,YAUEC,MAAA,QAAA,GAAA;IATI,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,UAAU;IACV,MAAM,KAAA;IACN,SAAS,QAAA;IACT,WAAS;IACV,MAAK;IACJ,cAAYA,MAAA,IAAA,CAAI,CAAC,OAAO,SAAS,KAAA;IACjC,SAAS,KAAA,MAAK,SAAM"}
1
+ {"version":3,"file":"table.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/widgets/table.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouTable } from 'dou-ui'\nimport type { TableColumn } from 'dou-ui'\nimport { computed, onMounted, ref } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { tablePropsOf } from './read-props'\nimport { fieldsOf, rowsToWorkbook, rowsOf } from './shared'\nimport type { TableWidgetColumn } from './types'\n\ndefineOptions({ name: 'DouDashboardTableWidget' })\n\nconst { props: raw, data, size, setWorkbook } = useDashboardWidget()\nconst props = computed(() => tablePropsOf(raw.value))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n/** Each row's key: its `rowKey` field, or its place in the list. */\nconst keys = computed(() => {\n const map = new WeakMap<object, string | number>()\n const field = props.value.rowKey\n rows.value.forEach((row, index) => map.set(row, field ? (row[field] as string | number) : index))\n return map\n})\nconst rowKey = (row: Record<string, unknown>) => keys.value.get(row) ?? ''\nconst number = new Intl.NumberFormat()\n/** The table's font, read once it is on the page, to measure texts with. */\nconst root = ref<{ $el: Element }>()\nconst font = ref('')\nonMounted(() => {\n const cell = root.value?.$el.querySelector('td, th')\n if (cell) font.value = getComputedStyle(cell).font\n})\nlet context: CanvasRenderingContext2D | null | undefined\n/** How wide a text is in the table's font, or about how wide before it is known. */\nfunction textWidth(text: string) {\n context ??=\n typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n if (context && font.value) {\n context.font = font.value\n return context.measureText(text).width\n }\n let width = 0\n for (const char of text) width += char.charCodeAt(0) > 0x2e7f ? 14 : 8.5\n return width\n}\n/** Room for the title and the first rows' texts, with the cell's padding; up to 240px. */\nfunction minWidthOf(title: string, texts: unknown[]) {\n let widest = textWidth(title)\n for (const text of texts) widest = Math.max(widest, textWidth(String(text ?? '')))\n return Math.min(240, Math.ceil(widest) + 28)\n}\nconst columns = computed<TableColumn[]>(() => {\n const first = rows.value[0]\n const list: TableWidgetColumn[] =\n props.value.columns ?? fieldsOf(rows.value).map((key) => ({ key }))\n return list.map(({ key, title }) => {\n const numeric = typeof first?.[key] === 'number'\n // numbers with digit groups, as in the stat widget\n const value = numeric\n ? (row: Record<string, unknown>) =>\n typeof row[key] === 'number' ? number.format(row[key] as number) : row[key]\n : undefined\n const sample = rows.value.slice(0, 20).map((row) => (value ? value(row) : row[key]))\n const least = minWidthOf(title || key, sample)\n return {\n key,\n title: title || key,\n align: numeric ? 'end' : undefined,\n ellipsis: true,\n // shares of the width follow the contents; never narrower than them\n width: least,\n minWidth: least,\n value,\n }\n })\n})\n// the export menu writes the rows as they are, numbers without digit groups\nsetWorkbook(() =>\n rowsToWorkbook(\n '',\n columns.value.map((column) => ({\n key: column.key as string,\n title: String(column.title),\n width: typeof column.width === 'number' ? column.width : undefined,\n })),\n rows.value,\n ),\n)\n</script>\n\n<template>\n <DouTable\n ref=\"root\"\n class=\"dou-dashboard-table\"\n :bordered=\"false\"\n :data=\"rows\"\n :columns=\"columns\"\n :row-key=\"rowKey\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n :virtual=\"rows.length > 100\"\n />\n</template>\n"],"mappings":";;;;;;;;;;EAWA,MAAM,EAAE,OAAO,KAAK,MAAM,MAAM,gBAAgB,mBAAmB;EACnE,MAAM,QAAQ,eAAe,aAAa,IAAI,KAAK,CAAC;EACpD,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;;EAEhE,MAAM,OAAO,eAAe;GAC1B,MAAM,sBAAM,IAAI,QAAiC;GACjD,MAAM,QAAQ,MAAM,MAAM;GAC1B,KAAK,MAAM,SAAS,KAAK,UAAU,IAAI,IAAI,KAAK,QAAS,IAAI,SAA6B,KAAK,CAAC;GAChG,OAAO;EACT,CAAC;EACD,MAAM,UAAU,QAAiC,KAAK,MAAM,IAAI,GAAG,KAAK;EACxE,MAAM,SAAS,IAAI,KAAK,aAAa;;EAErC,MAAM,OAAO,IAAsB;EACnC,MAAM,OAAO,IAAI,EAAE;EACnB,gBAAgB;GACd,MAAM,OAAO,KAAK,OAAO,IAAI,cAAc,QAAQ;GACnD,IAAI,MAAM,KAAK,QAAQ,iBAAiB,IAAI,CAAC,CAAC;EAChD,CAAC;EACD,IAAI;;EAEJ,SAAS,UAAU,MAAc;GAC/B,YACE,OAAO,aAAa,cAAc,OAAO,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI;GAC3F,IAAI,WAAW,KAAK,OAAO;IACzB,QAAQ,OAAO,KAAK;IACpB,OAAO,QAAQ,YAAY,IAAI,CAAC,CAAC;GACnC;GACA,IAAI,QAAQ;GACZ,KAAK,MAAM,QAAQ,MAAM,SAAS,KAAK,WAAW,CAAC,IAAI,QAAS,KAAK;GACrE,OAAO;EACT;;EAEA,SAAS,WAAW,OAAe,OAAkB;GACnD,IAAI,SAAS,UAAU,KAAK;GAC5B,KAAK,MAAM,QAAQ,OAAO,SAAS,KAAK,IAAI,QAAQ,UAAU,OAAO,QAAQ,EAAE,CAAC,CAAC;GACjF,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,EAAE;EAC7C;EACA,MAAM,UAAU,eAA8B;GAC5C,MAAM,QAAQ,KAAK,MAAM;GAGzB,QADE,MAAM,MAAM,WAAW,SAAS,KAAK,KAAK,CAAC,CAAC,KAAK,SAAS,EAAE,IAAI,EAAE,EAAA,CACxD,KAAK,EAAE,KAAK,YAAY;IAClC,MAAM,UAAU,OAAO,QAAQ,SAAS;IAExC,MAAM,QAAQ,WACT,QACC,OAAO,IAAI,SAAS,WAAW,OAAO,OAAO,IAAI,IAAc,IAAI,IAAI,OACzE,KAAA;IACJ,MAAM,SAAS,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,QAAS,QAAQ,MAAM,GAAG,IAAI,IAAI,IAAK;IACnF,MAAM,QAAQ,WAAW,SAAS,KAAK,MAAM;IAC7C,OAAO;KACL;KACA,OAAO,SAAS;KAChB,OAAO,UAAU,QAAQ,KAAA;KACzB,UAAU;KAEV,OAAO;KACP,UAAU;KACV;IACF;GACF,CAAC;EACH,CAAC;EAED,kBACE,eACE,IACA,QAAQ,MAAM,KAAK,YAAY;GAC7B,KAAK,OAAO;GACZ,OAAO,OAAO,OAAO,KAAK;GAC1B,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,KAAA;EAC3D,EAAE,GACF,KAAK,KACP,CACF;;GAIE,OAAAA,UAAA,GAAAC,YAUEC,MAAA,QAAA,GAAA;IATI,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,UAAU;IACV,MAAM,KAAA;IACN,SAAS,QAAA;IACT,WAAS;IACV,MAAK;IACJ,cAAYA,MAAA,IAAA,CAAI,CAAC,OAAO,SAAS,KAAA;IACjC,SAAS,KAAA,MAAK,SAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"text-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/text-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSegmentedControl, DouTextarea } from 'dou-ui'\nimport { useDashboardMessages } from '../locale'\nimport SettingsField from './settings-field.vue'\nimport type { TextWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTextSettings' })\n\nconst model = defineModel<TextWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst set = (patch: Partial<TextWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SettingsField :label=\"messages.text\">\n <DouTextarea\n :model-value=\"model.text ?? ''\"\n autosize\n :rows=\"4\"\n :aria-label=\"messages.text\"\n @update:model-value=\"(text) => set({ text })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.textSize\">\n <DouSegmentedControl\n :model-value=\"model.size ?? 'md'\"\n :options=\"[\n { value: 'sm', label: messages.sizeSmall },\n { value: 'md', label: messages.sizeMedium },\n { value: 'lg', label: messages.sizeLarge },\n ]\"\n :aria-label=\"messages.textSize\"\n @update:model-value=\"(size) => set({ size: size as TextWidgetProps['size'] })\"\n />\n </SettingsField>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"text-settings.js","names":["_sfc_main"],"sources":["../../src/widgets/text-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { DouSegmentedControl, DouTextarea } from 'dou-ui'\nimport { useDashboardMessages } from '../locale'\nimport SettingsField from './settings-field.vue'\nimport type { TextWidgetProps } from './types'\nimport { textPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardTextSettings' })\n\nconst model = defineModel<TextWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => textPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst set = (patch: Partial<TextWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SettingsField :label=\"messages.text\">\n <DouTextarea\n :model-value=\"view.text ?? ''\"\n autosize\n :rows=\"4\"\n :aria-label=\"messages.text\"\n @update:model-value=\"(text) => set({ text })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.textSize\">\n <DouSegmentedControl\n :model-value=\"view.size ?? 'md'\"\n :options=\"[\n { value: 'sm', label: messages.sizeSmall },\n { value: 'md', label: messages.sizeMedium },\n { value: 'lg', label: messages.sizeLarge },\n ]\"\n :aria-label=\"messages.textSize\"\n @update:model-value=\"(size) => set({ size: size as TextWidgetProps['size'] })\"\n />\n </SettingsField>\n </div>\n</template>\n"],"mappings":""}
@@ -1,7 +1,8 @@
1
1
  import { useDashboardMessages } from "../locale.js";
2
+ import { textPropsOf } from "./read-props.js";
2
3
  import settings_field_default from "./settings-field.js";
3
4
  import { DouSegmentedControl, DouTextarea } from "dou-ui";
4
- import { createElementBlock, createVNode, defineComponent, openBlock, unref, useModel, withCtx } from "vue";
5
+ import { computed, createElementBlock, createVNode, defineComponent, openBlock, unref, useModel, withCtx } from "vue";
5
6
  // src/widgets/text-settings.vue?vue&type=script&setup=true&lang.ts
6
7
  var _hoisted_1 = { class: "dou-dashboard__settings" };
7
8
  var text_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
@@ -14,6 +15,7 @@ var text_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
14
15
  emits: ["update:modelValue"],
15
16
  setup(__props) {
16
17
  const model = useModel(__props, "modelValue");
18
+ const view = computed(() => textPropsOf(model.value));
17
19
  const messages = useDashboardMessages();
18
20
  const set = (patch) => model.value = {
19
21
  ...model.value,
@@ -22,7 +24,7 @@ var text_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
22
24
  return (_ctx, _cache) => {
23
25
  return openBlock(), createElementBlock("div", _hoisted_1, [createVNode(settings_field_default, { label: unref(messages).text }, {
24
26
  default: withCtx(() => [createVNode(unref(DouTextarea), {
25
- "model-value": model.value.text ?? "",
27
+ "model-value": view.value.text ?? "",
26
28
  autosize: "",
27
29
  rows: 4,
28
30
  "aria-label": unref(messages).text,
@@ -31,7 +33,7 @@ var text_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
31
33
  _: 1
32
34
  }, 8, ["label"]), createVNode(settings_field_default, { label: unref(messages).textSize }, {
33
35
  default: withCtx(() => [createVNode(unref(DouSegmentedControl), {
34
- "model-value": model.value.size ?? "md",
36
+ "model-value": view.value.size ?? "md",
35
37
  options: [
36
38
  {
37
39
  value: "sm",
@@ -1 +1 @@
1
- {"version":3,"file":"text-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SettingsField","_unref","_withCtx"],"sources":["../../src/widgets/text-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSegmentedControl, DouTextarea } from 'dou-ui'\nimport { useDashboardMessages } from '../locale'\nimport SettingsField from './settings-field.vue'\nimport type { TextWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTextSettings' })\n\nconst model = defineModel<TextWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst set = (patch: Partial<TextWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SettingsField :label=\"messages.text\">\n <DouTextarea\n :model-value=\"model.text ?? ''\"\n autosize\n :rows=\"4\"\n :aria-label=\"messages.text\"\n @update:model-value=\"(text) => set({ text })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.textSize\">\n <DouSegmentedControl\n :model-value=\"model.size ?? 'md'\"\n :options=\"[\n { value: 'sm', label: messages.sizeSmall },\n { value: 'md', label: messages.sizeMedium },\n { value: 'lg', label: messages.sizeLarge },\n ]\"\n :aria-label=\"messages.textSize\"\n @update:model-value=\"(size) => set({ size: size as TextWidgetProps['size'] })\"\n />\n </SettingsField>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;EAQA,MAAM,QAAQA,SAA4B,SAAA,YAAmB;EAC7D,MAAM,WAAW,qBAAqB;EACtC,MAAM,OAAO,UAAqC,MAAM,QAAQ;GAAE,GAAG,MAAM;GAAO,GAAG;EAAM;;GAIzF,OAAAC,UAAA,GAAAC,mBAsBM,OAtBN,YAsBM,CArBJC,YAQgBC,wBAAA,EARA,OAAOC,MAAA,QAAA,CAAQ,CAAC,K;IAC9B,SAAAC,cAME,CANFH,YAMEE,MAAA,WAAA,GAAA;KALC,eAAa,MAAA,MAAM,QAAI;KACxB,UAAA;KACC,MAAM;KACN,cAAYA,MAAA,QAAA,CAAQ,CAAC;KACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,SAAS,IAAG,EAAG,KAAI,CAAA;;;G,kBAG7CF,YAWgBC,wBAAA,EAXA,OAAOC,MAAA,QAAA,CAAQ,CAAC,S;IAC9B,SAAAC,cASE,CATFH,YASEE,MAAA,mBAAA,GAAA;KARC,eAAa,MAAA,MAAM,QAAI;KACvB,SAAO;MAAoC;OAAA,OAAA;OAAA,OAAAA,MAAA,QAAA,CAAQ,CAAC;MAAS;MAAoC;OAAA,OAAA;OAAA,OAAAA,MAAA,QAAA,CAAQ,CAAC;MAAU;MAAoC;OAAA,OAAA;OAAA,OAAAA,MAAA,QAAA,CAAQ,CAAC;MAAS;;KAK1K,cAAYA,MAAA,QAAA,CAAQ,CAAC;KACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,SAAS,IAAG,EAAS,KAAI,CAAA"}
1
+ {"version":3,"file":"text-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SettingsField","_unref","_withCtx"],"sources":["../../src/widgets/text-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { DouSegmentedControl, DouTextarea } from 'dou-ui'\nimport { useDashboardMessages } from '../locale'\nimport SettingsField from './settings-field.vue'\nimport type { TextWidgetProps } from './types'\nimport { textPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardTextSettings' })\n\nconst model = defineModel<TextWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => textPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst set = (patch: Partial<TextWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SettingsField :label=\"messages.text\">\n <DouTextarea\n :model-value=\"view.text ?? ''\"\n autosize\n :rows=\"4\"\n :aria-label=\"messages.text\"\n @update:model-value=\"(text) => set({ text })\"\n />\n </SettingsField>\n <SettingsField :label=\"messages.textSize\">\n <DouSegmentedControl\n :model-value=\"view.size ?? 'md'\"\n :options=\"[\n { value: 'sm', label: messages.sizeSmall },\n { value: 'md', label: messages.sizeMedium },\n { value: 'lg', label: messages.sizeLarge },\n ]\"\n :aria-label=\"messages.textSize\"\n @update:model-value=\"(size) => set({ size: size as TextWidgetProps['size'] })\"\n />\n </SettingsField>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;EAUA,MAAM,QAAQA,SAA4B,SAAA,YAAmB;EAE7D,MAAM,OAAO,eAAe,YAAY,MAAM,KAAgC,CAAC;EAC/E,MAAM,WAAW,qBAAqB;EACtC,MAAM,OAAO,UAAqC,MAAM,QAAQ;GAAE,GAAG,MAAM;GAAO,GAAG;EAAM;;GAIzF,OAAAC,UAAA,GAAAC,mBAsBM,OAtBN,YAsBM,CArBJC,YAQgBC,wBAAA,EARA,OAAOC,MAAA,QAAA,CAAQ,CAAC,K;IAC9B,SAAAC,cAME,CANFH,YAMEE,MAAA,WAAA,GAAA;KALC,eAAa,KAAA,MAAK,QAAI;KACvB,UAAA;KACC,MAAM;KACN,cAAYA,MAAA,QAAA,CAAQ,CAAC;KACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,SAAS,IAAG,EAAG,KAAI,CAAA;;;G,kBAG7CF,YAWgBC,wBAAA,EAXA,OAAOC,MAAA,QAAA,CAAQ,CAAC,S;IAC9B,SAAAC,cASE,CATFH,YASEE,MAAA,mBAAA,GAAA;KARC,eAAa,KAAA,MAAK,QAAI;KACtB,SAAO;MAAoC;OAAA,OAAA;OAAA,OAAAA,MAAA,QAAA,CAAQ,CAAC;MAAS;MAAoC;OAAA,OAAA;OAAA,OAAAA,MAAA,QAAA,CAAQ,CAAC;MAAU;MAAoC;OAAA,OAAA;OAAA,OAAAA,MAAA,QAAA,CAAQ,CAAC;MAAS;;KAK1K,cAAYA,MAAA,QAAA,CAAQ,CAAC;KACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,SAAS,IAAG,EAAS,KAAI,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":["_sfc_main"],"sources":["../../src/widgets/text.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useDashboardWidget } from '../widget/context'\nimport type { TextWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTextWidget' })\n\nconst { props } = useDashboardWidget<TextWidgetProps>()\n</script>\n\n<template>\n <div :class=\"['dou-dashboard-text', `is-${props.size ?? 'md'}`]\">{{ props.text }}</div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"text.js","names":["_sfc_main"],"sources":["../../src/widgets/text.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { textPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardTextWidget' })\n\nconst { props: raw } = useDashboardWidget()\nconst props = computed(() => textPropsOf(raw.value))\n</script>\n\n<template>\n <div :class=\"['dou-dashboard-text', `is-${props.size ?? 'md'}`]\">{{ props.text }}</div>\n</template>\n"],"mappings":""}
@@ -1,13 +1,15 @@
1
1
  import { useDashboardWidget } from "../widget/context.js";
2
- import { createElementBlock, defineComponent, normalizeClass, openBlock, toDisplayString, unref } from "vue";
2
+ import { textPropsOf } from "./read-props.js";
3
+ import { computed, createElementBlock, defineComponent, normalizeClass, openBlock, toDisplayString } from "vue";
3
4
  // src/widgets/text.vue?vue&type=script&setup=true&lang.ts
4
5
  var text_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
5
6
  name: "DouDashboardTextWidget",
6
7
  __name: "text",
7
8
  setup(__props) {
8
- const { props } = useDashboardWidget();
9
+ const { props: raw } = useDashboardWidget();
10
+ const props = computed(() => textPropsOf(raw.value));
9
11
  return (_ctx, _cache) => {
10
- return openBlock(), createElementBlock("div", { class: normalizeClass(["dou-dashboard-text", `is-${unref(props).size ?? "md"}`]) }, toDisplayString(unref(props).text), 3);
12
+ return openBlock(), createElementBlock("div", { class: normalizeClass(["dou-dashboard-text", `is-${props.value.size ?? "md"}`]) }, toDisplayString(props.value.text), 3);
11
13
  };
12
14
  }
13
15
  });
@@ -1 +1 @@
1
- {"version":3,"file":"text.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_unref","_toDisplayString"],"sources":["../../src/widgets/text.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useDashboardWidget } from '../widget/context'\nimport type { TextWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardTextWidget' })\n\nconst { props } = useDashboardWidget<TextWidgetProps>()\n</script>\n\n<template>\n <div :class=\"['dou-dashboard-text', `is-${props.size ?? 'md'}`]\">{{ props.text }}</div>\n</template>\n"],"mappings":";;;;;;;EAMA,MAAM,EAAE,UAAU,mBAAoC;;GAIpD,OAAAA,UAAA,GAAAC,mBAAuF,OAAA,EAAjF,OAAKC,eAAA,CAAA,sBAAA,MAA+BC,MAAA,KAAA,CAAK,CAAC,QAAI,MAAA,CAAA,EAAgB,GAAAC,gBAAAD,MAAA,KAAA,CAAK,CAAC,IAAI,GAAA,CAAA"}
1
+ {"version":3,"file":"text.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_toDisplayString"],"sources":["../../src/widgets/text.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { textPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardTextWidget' })\n\nconst { props: raw } = useDashboardWidget()\nconst props = computed(() => textPropsOf(raw.value))\n</script>\n\n<template>\n <div :class=\"['dou-dashboard-text', `is-${props.size ?? 'md'}`]\">{{ props.text }}</div>\n</template>\n"],"mappings":";;;;;;;;EAOA,MAAM,EAAE,OAAO,QAAQ,mBAAmB;EAC1C,MAAM,QAAQ,eAAe,YAAY,IAAI,KAAK,CAAC;;GAIjD,OAAAA,UAAA,GAAAC,mBAAuF,OAAA,EAAjF,OAAKC,eAAA,CAAA,sBAAA,MAA+B,MAAA,MAAM,QAAI,MAAA,CAAA,EAAgB,GAAAC,gBAAA,MAAA,MAAM,IAAI,GAAA,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dou-ui/dashboard",
3
- "version": "0.1.0-alpha.4",
3
+ "version": "0.1.0-alpha.5",
4
4
  "description": "DouUI 的仪表盘:可拖动、可缩放的网格布局与仪表盘设计器",
5
5
  "keywords": [
6
6
  "vue",
@@ -67,9 +67,9 @@
67
67
  "build": "vite build && vue-tsc -p tsconfig.build.json && bun scripts/build-style.ts"
68
68
  },
69
69
  "peerDependencies": {
70
- "@dou-ui/chart": "0.1.0-alpha.4",
71
- "@dou-ui/pivot": "0.1.0-alpha.4",
72
- "dou-ui": "0.1.0-alpha.4",
70
+ "@dou-ui/chart": "0.1.0-alpha.5",
71
+ "@dou-ui/pivot": "0.1.0-alpha.5",
72
+ "dou-ui": "0.1.0-alpha.5",
73
73
  "vue": "^3.5.0",
74
74
  "yjs": "^13.6.0"
75
75
  },
@@ -85,12 +85,12 @@
85
85
  }
86
86
  },
87
87
  "dependencies": {
88
- "@dou-ui/icons": "0.1.0-alpha.4",
89
- "@dou-ui/sheet": "0.1.0-alpha.4"
88
+ "@dou-ui/icons": "0.1.0-alpha.5",
89
+ "@dou-ui/sheet": "0.1.0-alpha.5"
90
90
  },
91
91
  "devDependencies": {
92
- "@dou-ui/chart": "0.1.0-alpha.4",
93
- "@dou-ui/pivot": "0.1.0-alpha.4",
92
+ "@dou-ui/chart": "0.1.0-alpha.5",
93
+ "@dou-ui/pivot": "0.1.0-alpha.5",
94
94
  "y-protocols": "^1.0.7",
95
95
  "yjs": "^13.6.33"
96
96
  },