@dou-ui/dashboard 0.1.0-alpha.3 → 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 (97) 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/core/document.js +10 -1
  10. package/dist/core/document.js.map +1 -1
  11. package/dist/core/history.js +23 -0
  12. package/dist/core/history.js.map +1 -1
  13. package/dist/core/transaction.js +8 -2
  14. package/dist/core/transaction.js.map +1 -1
  15. package/dist/dashboard/comment-button.js +6 -0
  16. package/dist/dashboard/comment-button.js.map +1 -0
  17. package/dist/dashboard/comment-button.vue_vue_type_script_setup_true_lang.js +59 -0
  18. package/dist/dashboard/comment-button.vue_vue_type_script_setup_true_lang.js.map +1 -0
  19. package/dist/dashboard/comment-card.js +6 -0
  20. package/dist/dashboard/comment-card.js.map +1 -0
  21. package/dist/dashboard/comment-card.vue_vue_type_script_setup_true_lang.js +128 -0
  22. package/dist/dashboard/comment-card.vue_vue_type_script_setup_true_lang.js.map +1 -0
  23. package/dist/dashboard/comments.js +144 -0
  24. package/dist/dashboard/comments.js.map +1 -0
  25. package/dist/dashboard/dashboard.js.map +1 -1
  26. package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js +132 -20
  27. package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -1
  28. package/dist/dashboard/error-boundary.js +64 -0
  29. package/dist/dashboard/error-boundary.js.map +1 -0
  30. package/dist/dashboard/frame-context.js.map +1 -1
  31. package/dist/dashboard/widget-body.js.map +1 -1
  32. package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js +53 -12
  33. package/dist/dashboard/widget-body.vue_vue_type_script_setup_true_lang.js.map +1 -1
  34. package/dist/dashboard/widget-frame.js.map +1 -1
  35. package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +14 -2
  36. package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -1
  37. package/dist/dashboard/widget-settings.js.map +1 -1
  38. package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js +31 -5
  39. package/dist/dashboard/widget-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/locale.js +12 -0
  42. package/dist/locale.js.map +1 -1
  43. package/dist/pivot/pivot-settings.js.map +1 -1
  44. package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js +6 -4
  45. package/dist/pivot/pivot-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  46. package/dist/pivot/pivot.js.map +1 -1
  47. package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js +4 -2
  48. package/dist/pivot/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -1
  49. package/dist/pivot/read-props.js +44 -0
  50. package/dist/pivot/read-props.js.map +1 -0
  51. package/dist/style.css +1 -1
  52. package/dist/style.js +2 -3
  53. package/dist/types/chart/read-props.d.ts +3 -0
  54. package/dist/types/core/document.d.ts +3 -2
  55. package/dist/types/core/history.d.ts +7 -1
  56. package/dist/types/core/transaction.d.ts +10 -1
  57. package/dist/types/core/types.d.ts +5 -0
  58. package/dist/types/dashboard/comment-button.vue.d.ts +15 -0
  59. package/dist/types/dashboard/comment-card.vue.d.ts +13 -0
  60. package/dist/types/dashboard/comments.d.ts +44 -0
  61. package/dist/types/dashboard/dashboard.vue.d.ts +12 -0
  62. package/dist/types/dashboard/error-boundary.d.ts +12 -0
  63. package/dist/types/dashboard/frame-context.d.ts +4 -0
  64. package/dist/types/dashboard/types.d.ts +47 -0
  65. package/dist/types/dashboard/widget-body.vue.d.ts +2 -0
  66. package/dist/types/dashboard/widget-settings.vue.d.ts +4 -0
  67. package/dist/types/index.d.ts +22 -1
  68. package/dist/types/locale.d.ts +8 -0
  69. package/dist/types/pivot/read-props.d.ts +3 -0
  70. package/dist/types/widgets/index.d.ts +1 -1
  71. package/dist/types/widgets/read-props.d.ts +4 -0
  72. package/dist/types/widgets/shared.d.ts +20 -4
  73. package/dist/widgets/index.js +2 -2
  74. package/dist/widgets/index.js.map +1 -1
  75. package/dist/widgets/read-props.js +52 -0
  76. package/dist/widgets/read-props.js.map +1 -0
  77. package/dist/widgets/shared.js +27 -5
  78. package/dist/widgets/shared.js.map +1 -1
  79. package/dist/widgets/stat-settings.js.map +1 -1
  80. package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js +12 -10
  81. package/dist/widgets/stat-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  82. package/dist/widgets/stat.js.map +1 -1
  83. package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js +10 -13
  84. package/dist/widgets/stat.vue_vue_type_script_setup_true_lang.js.map +1 -1
  85. package/dist/widgets/table-settings.js.map +1 -1
  86. package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js +6 -4
  87. package/dist/widgets/table-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  88. package/dist/widgets/table.js.map +1 -1
  89. package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js +3 -1
  90. package/dist/widgets/table.vue_vue_type_script_setup_true_lang.js.map +1 -1
  91. package/dist/widgets/text-settings.js.map +1 -1
  92. package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js +5 -3
  93. package/dist/widgets/text-settings.vue_vue_type_script_setup_true_lang.js.map +1 -1
  94. package/dist/widgets/text.js.map +1 -1
  95. package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js +5 -3
  96. package/dist/widgets/text.vue_vue_type_script_setup_true_lang.js.map +1 -1
  97. package/package.json +8 -8
package/dist/locale.js CHANGED
@@ -22,6 +22,8 @@ var zhCN = {
22
22
  nothingToExport: "没有可导出的数据",
23
23
  duplicate: "复制一份",
24
24
  remove: "删除",
25
+ comment: "评论",
26
+ comments: "{count} 条评论",
25
27
  settingsTitle: "{title}的设置",
26
28
  titleField: "标题",
27
29
  added: "已添加 {item}",
@@ -29,6 +31,8 @@ var zhCN = {
29
31
  unknownType: "没有注册类型为 {type} 的格子",
30
32
  loading: "加载中",
31
33
  error: "加载失败",
34
+ renderError: "无法显示",
35
+ settingsError: "无法显示设置",
32
36
  empty: "暂无数据",
33
37
  retry: "重试",
34
38
  emptyTitle: "还没有格子",
@@ -94,6 +98,8 @@ var zhTW = {
94
98
  nothingToExport: "沒有可匯出的資料",
95
99
  duplicate: "複製一份",
96
100
  remove: "刪除",
101
+ comment: "評論",
102
+ comments: "{count} 則評論",
97
103
  settingsTitle: "{title}的設定",
98
104
  titleField: "標題",
99
105
  added: "已新增 {item}",
@@ -101,6 +107,8 @@ var zhTW = {
101
107
  unknownType: "沒有註冊類型為 {type} 的格子",
102
108
  loading: "載入中",
103
109
  error: "載入失敗",
110
+ renderError: "無法顯示",
111
+ settingsError: "無法顯示設定",
104
112
  empty: "暫無資料",
105
113
  retry: "重試",
106
114
  emptyTitle: "還沒有格子",
@@ -166,6 +174,8 @@ var en = {
166
174
  nothingToExport: "There is no data to export",
167
175
  duplicate: "Duplicate",
168
176
  remove: "Remove",
177
+ comment: "Comment",
178
+ comments: "{count} comments",
169
179
  settingsTitle: "{title} settings",
170
180
  titleField: "Title",
171
181
  added: "Added {item}",
@@ -173,6 +183,8 @@ var en = {
173
183
  unknownType: "No widget type “{type}” is registered",
174
184
  loading: "Loading",
175
185
  error: "Couldn’t load",
186
+ renderError: "Couldn’t display",
187
+ settingsError: "Couldn’t display the settings",
176
188
  empty: "No data",
177
189
  retry: "Retry",
178
190
  emptyTitle: "No widgets yet",
@@ -1 +1 @@
1
- {"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface DashboardMessages {\n /** The grid layout's accessible name. */\n layout: string\n /** What an item of the grid is called by a screen reader. */\n item: string\n /** Read after an item's name while the layout can be edited. */\n itemHint: string\n /** An item that can't be moved: `{item}`. */\n locked: string\n /** An item's place: `{x}` `{y}` (from 1), `{w}` `{h}` (in columns and rows). */\n position: string\n /** An item's place when the grid has one column: `{n}` of `{count}` (from 1). */\n order: string\n /** An item picked up with the keyboard: `{item}` and `{position}`. */\n grabbed: string\n /** An item put down, with the keyboard or the pointer: `{item}` and `{position}`. */\n dropped: string\n /** A move or resize undone with Escape (or a drop outside the grid): `{item}`. */\n cancelled: string\n /** The handle in an item's corner. */\n resize: string\n /** The dashboard's accessible name. */\n dashboard: string\n /** The menu button in a widget's title bar. */\n widgetMenu: string\n /** Menu items. */\n settings: string\n fullscreen: string\n /** The menu of file types a widget's content can be exported as. */\n export: string\n /** A failed export, over the widget's content: `{name}` (the file), `{reason}`. */\n exportFailed: string\n /** Read out once the file is saved: `{name}`. */\n exported: string\n /** Why a widget can't be exported: it has no data, such as a chart without its fields. */\n nothingToExport: string\n duplicate: string\n remove: string\n /** The settings drawer's title: `{title}`. */\n settingsTitle: string\n /** The title field in the settings drawer. */\n titleField: string\n /** Read when a widget is added, copied or removed: `{item}`. */\n added: string\n removed: string\n /** A widget whose type isn't registered: `{type}`. */\n unknownType: string\n /** A widget's status. */\n loading: string\n error: string\n empty: string\n retry: string\n /** A dashboard without widgets, while editing. */\n emptyTitle: string\n emptyHint: string\n /** The list of widgets to add. */\n palette: string\n /** A widget in that list: `{label}`. */\n paletteItem: string\n /** In the title bar of a widget that set a filter: `{value}`. */\n filteredBy: string\n peerMoving: string\n peerResizing: string\n peerSettings: string\n /** The button clearing that filter: `{value}`. */\n clearFilter: string\n /** The filter bar's accessible name. */\n filterBar: string\n /** A filter set by a widget, in the filter bar: `{title}` and `{value}`. */\n linkedFilter: string\n /** Clears every filter. */\n clearFilters: string\n /** Settings of the built-in widgets. */\n source: string\n noSource: string\n field: string\n value: string\n prefix: string\n suffix: string\n precision: string\n trend: string\n delta: string\n /** The change under a number: `{value}`, e.g. `+12.5%`. */\n deltaText: string\n text: string\n textSize: string\n sizeSmall: string\n sizeMedium: string\n sizeLarge: string\n columns: string\n /** The title of a table column, while it has none: `{field}`. */\n columnTitle: string\n chartKind: string\n chartLine: string\n chartArea: string\n chartBar: string\n chartPie: string\n xField: string\n yFields: string\n stacked: string\n horizontal: string\n /** The filter set by clicking a chart. */\n chartFilter: string\n chartFilterHint: string\n /** Whether clicking a pivot table's cell filters the other widgets. */\n pivotFilter: string\n}\n\nconst zhCN: DashboardMessages = {\n layout: '网格布局',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向键移动、Shift 加方向键调整大小',\n locked: '{item} 已锁定,不能移动',\n position: '第 {x} 列第 {y} 行,宽 {w} 列,高 {h} 行',\n order: '第 {n} 个,共 {count} 个',\n grabbed: '已拿起 {item},{position}。方向键移动,Shift 加方向键调整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原处',\n resize: '调整大小',\n dashboard: '仪表盘',\n widgetMenu: '格子操作',\n settings: '设置',\n fullscreen: '全屏查看',\n export: '导出',\n exportFailed: '无法导出 {name}:{reason}',\n exported: '已导出 {name}',\n nothingToExport: '没有可导出的数据',\n duplicate: '复制一份',\n remove: '删除',\n settingsTitle: '{title}的设置',\n titleField: '标题',\n added: '已添加 {item}',\n removed: '已删除 {item}',\n unknownType: '没有注册类型为 {type} 的格子',\n loading: '加载中',\n error: '加载失败',\n empty: '暂无数据',\n retry: '重试',\n emptyTitle: '还没有格子',\n emptyHint: '从列表里拖进来,或点一下添加',\n palette: '添加格子',\n paletteItem: '添加{label}',\n filteredBy: '已按 {value} 筛选',\n peerMoving: '{name} 正在移动',\n peerResizing: '{name} 正在调整大小',\n peerSettings: '{name} 正在修改设置',\n clearFilter: '清除筛选:{value}',\n filterBar: '筛选',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除筛选',\n source: '数据源',\n noSource: '不使用数据源',\n field: '字段',\n value: '数值',\n prefix: '前缀',\n suffix: '后缀',\n precision: '小数位数',\n trend: '迷你图字段',\n delta: '变化率字段',\n deltaText: '较上期 {value}',\n text: '文字',\n textSize: '字号',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '列',\n columnTitle: '{field} 的标题',\n chartKind: '图表',\n chartLine: '折线图',\n chartArea: '面积图',\n chartBar: '柱状图',\n chartPie: '饼图',\n xField: '分类或时间',\n yFields: '数值',\n stacked: '堆叠',\n horizontal: '横向',\n chartFilter: '点击时筛选',\n chartFilterHint: '点图表里的一项时,用这个名字筛选其他格子;留空则不筛选',\n pivotFilter: '点击单元格时,按它所在的分组筛选其他格子',\n}\n\nconst zhTW: DashboardMessages = {\n layout: '網格版面',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向鍵移動、Shift 加方向鍵調整大小',\n locked: '{item} 已鎖定,無法移動',\n position: '第 {x} 欄第 {y} 列,寬 {w} 欄,高 {h} 列',\n order: '第 {n} 個,共 {count} 個',\n grabbed: '已拿起 {item},{position}。方向鍵移動,Shift 加方向鍵調整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原處',\n resize: '調整大小',\n dashboard: '儀表板',\n widgetMenu: '格子操作',\n settings: '設定',\n fullscreen: '全螢幕檢視',\n export: '匯出',\n exportFailed: '無法匯出 {name}:{reason}',\n exported: '已匯出 {name}',\n nothingToExport: '沒有可匯出的資料',\n duplicate: '複製一份',\n remove: '刪除',\n settingsTitle: '{title}的設定',\n titleField: '標題',\n added: '已新增 {item}',\n removed: '已刪除 {item}',\n unknownType: '沒有註冊類型為 {type} 的格子',\n loading: '載入中',\n error: '載入失敗',\n empty: '暫無資料',\n retry: '重試',\n emptyTitle: '還沒有格子',\n emptyHint: '從清單拖進來,或點一下新增',\n palette: '新增格子',\n paletteItem: '新增{label}',\n filteredBy: '已按 {value} 篩選',\n peerMoving: '{name} 正在移動',\n peerResizing: '{name} 正在調整大小',\n peerSettings: '{name} 正在修改設定',\n clearFilter: '清除篩選:{value}',\n filterBar: '篩選',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除篩選',\n source: '資料來源',\n noSource: '不使用資料來源',\n field: '欄位',\n value: '數值',\n prefix: '前綴',\n suffix: '後綴',\n precision: '小數位數',\n trend: '迷你圖欄位',\n delta: '變化率欄位',\n deltaText: '較上期 {value}',\n text: '文字',\n textSize: '字號',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '欄',\n columnTitle: '{field} 的標題',\n chartKind: '圖表',\n chartLine: '折線圖',\n chartArea: '面積圖',\n chartBar: '長條圖',\n chartPie: '圓餅圖',\n xField: '分類或時間',\n yFields: '數值',\n stacked: '堆疊',\n horizontal: '橫向',\n chartFilter: '點擊時篩選',\n chartFilterHint: '點圖表裡的一項時,用這個名字篩選其他格子;留空則不篩選',\n pivotFilter: '點擊儲存格時,依其所在的分組篩選其他格子',\n}\n\nconst en: DashboardMessages = {\n layout: 'Grid layout',\n item: 'tile',\n itemHint: 'Press Enter to pick up, then arrow keys to move and Shift with arrow keys to resize',\n locked: '{item} is locked and can’t be moved',\n position: 'column {x}, row {y}, {w} columns wide, {h} rows high',\n order: '{n} of {count}',\n grabbed:\n 'Picked up {item}, {position}. Arrow keys move, Shift with arrow keys resizes, Enter puts down, Escape cancels',\n dropped: 'Put down {item}, {position}',\n cancelled: 'Cancelled, {item} is back where it was',\n resize: 'Resize',\n dashboard: 'Dashboard',\n widgetMenu: 'Widget actions',\n settings: 'Settings',\n fullscreen: 'View full screen',\n export: 'Export',\n exportFailed: \"Couldn't export {name}: {reason}\",\n exported: 'Exported {name}',\n nothingToExport: 'There is no data to export',\n duplicate: 'Duplicate',\n remove: 'Remove',\n settingsTitle: '{title} settings',\n titleField: 'Title',\n added: 'Added {item}',\n removed: 'Removed {item}',\n unknownType: 'No widget type “{type}” is registered',\n loading: 'Loading',\n error: 'Couldn’t load',\n empty: 'No data',\n retry: 'Retry',\n emptyTitle: 'No widgets yet',\n emptyHint: 'Drag one in from the list, or click to add it',\n palette: 'Add widget',\n paletteItem: 'Add {label}',\n filteredBy: 'Filtered by {value}',\n peerMoving: '{name} is moving it',\n peerResizing: '{name} is resizing it',\n peerSettings: '{name} is changing its settings',\n clearFilter: 'Clear filter: {value}',\n filterBar: 'Filters',\n linkedFilter: '{title}: {value}',\n clearFilters: 'Clear filters',\n source: 'Source',\n noSource: 'No source',\n field: 'Field',\n value: 'Value',\n prefix: 'Prefix',\n suffix: 'Suffix',\n precision: 'Decimal places',\n trend: 'Sparkline field',\n delta: 'Change field',\n deltaText: '{value} vs. last period',\n text: 'Text',\n textSize: 'Size',\n sizeSmall: 'Small',\n sizeMedium: 'Medium',\n sizeLarge: 'Large',\n columns: 'Columns',\n columnTitle: 'Title of {field}',\n chartKind: 'Chart',\n chartLine: 'Line',\n chartArea: 'Area',\n chartBar: 'Bar',\n chartPie: 'Pie',\n xField: 'Category or time',\n yFields: 'Values',\n stacked: 'Stacked',\n horizontal: 'Horizontal',\n chartFilter: 'Filter on click',\n chartFilterHint:\n 'Clicking an item filters the other widgets by this name; leave empty to not filter',\n pivotFilter: 'Clicking a cell filters the other widgets by its groups',\n}\n\nexport const dashboardLocales: Record<string, DashboardMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type DashboardMessagesOverride = Partial<DashboardMessages>\n\n/**\n * The dashboard's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useDashboardMessages(\n override?: MaybeRefOrGetter<DashboardMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<DashboardMessages>(() => {\n const name = locale.value.name\n const base =\n dashboardLocales[name] ??\n dashboardLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":"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"}
1
+ {"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface DashboardMessages {\n /** The grid layout's accessible name. */\n layout: string\n /** What an item of the grid is called by a screen reader. */\n item: string\n /** Read after an item's name while the layout can be edited. */\n itemHint: string\n /** An item that can't be moved: `{item}`. */\n locked: string\n /** An item's place: `{x}` `{y}` (from 1), `{w}` `{h}` (in columns and rows). */\n position: string\n /** An item's place when the grid has one column: `{n}` of `{count}` (from 1). */\n order: string\n /** An item picked up with the keyboard: `{item}` and `{position}`. */\n grabbed: string\n /** An item put down, with the keyboard or the pointer: `{item}` and `{position}`. */\n dropped: string\n /** A move or resize undone with Escape (or a drop outside the grid): `{item}`. */\n cancelled: string\n /** The handle in an item's corner. */\n resize: string\n /** The dashboard's accessible name. */\n dashboard: string\n /** The menu button in a widget's title bar. */\n widgetMenu: string\n /** Menu items. */\n settings: string\n fullscreen: string\n /** The menu of file types a widget's content can be exported as. */\n export: string\n /** A failed export, over the widget's content: `{name}` (the file), `{reason}`. */\n exportFailed: string\n /** Read out once the file is saved: `{name}`. */\n exported: string\n /** Why a widget can't be exported: it has no data, such as a chart without its fields. */\n nothingToExport: string\n duplicate: string\n remove: string\n /** The comment button and the card of a widget's discussions. */\n comment: string\n /** The comment button of a widget with discussions; `{count}` is how many are open. */\n comments: string\n /** The settings drawer's title: `{title}`. */\n settingsTitle: string\n /** The title field in the settings drawer. */\n titleField: string\n /** Read when a widget is added, copied or removed: `{item}`. */\n added: string\n removed: string\n /** A widget whose type isn't registered: `{type}`. */\n unknownType: string\n /** A widget's status. */\n loading: string\n error: string\n /** A widget that failed to show, e.g. for props it can't use. */\n renderError: string\n /** A widget's settings form that failed to show. */\n settingsError: string\n empty: string\n retry: string\n /** A dashboard without widgets, while editing. */\n emptyTitle: string\n emptyHint: string\n /** The list of widgets to add. */\n palette: string\n /** A widget in that list: `{label}`. */\n paletteItem: string\n /** In the title bar of a widget that set a filter: `{value}`. */\n filteredBy: string\n peerMoving: string\n peerResizing: string\n peerSettings: string\n /** The button clearing that filter: `{value}`. */\n clearFilter: string\n /** The filter bar's accessible name. */\n filterBar: string\n /** A filter set by a widget, in the filter bar: `{title}` and `{value}`. */\n linkedFilter: string\n /** Clears every filter. */\n clearFilters: string\n /** Settings of the built-in widgets. */\n source: string\n noSource: string\n field: string\n value: string\n prefix: string\n suffix: string\n precision: string\n trend: string\n delta: string\n /** The change under a number: `{value}`, e.g. `+12.5%`. */\n deltaText: string\n text: string\n textSize: string\n sizeSmall: string\n sizeMedium: string\n sizeLarge: string\n columns: string\n /** The title of a table column, while it has none: `{field}`. */\n columnTitle: string\n chartKind: string\n chartLine: string\n chartArea: string\n chartBar: string\n chartPie: string\n xField: string\n yFields: string\n stacked: string\n horizontal: string\n /** The filter set by clicking a chart. */\n chartFilter: string\n chartFilterHint: string\n /** Whether clicking a pivot table's cell filters the other widgets. */\n pivotFilter: string\n}\n\nconst zhCN: DashboardMessages = {\n layout: '网格布局',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向键移动、Shift 加方向键调整大小',\n locked: '{item} 已锁定,不能移动',\n position: '第 {x} 列第 {y} 行,宽 {w} 列,高 {h} 行',\n order: '第 {n} 个,共 {count} 个',\n grabbed: '已拿起 {item},{position}。方向键移动,Shift 加方向键调整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原处',\n resize: '调整大小',\n dashboard: '仪表盘',\n widgetMenu: '格子操作',\n settings: '设置',\n fullscreen: '全屏查看',\n export: '导出',\n exportFailed: '无法导出 {name}:{reason}',\n exported: '已导出 {name}',\n nothingToExport: '没有可导出的数据',\n duplicate: '复制一份',\n remove: '删除',\n comment: '评论',\n comments: '{count} 条评论',\n settingsTitle: '{title}的设置',\n titleField: '标题',\n added: '已添加 {item}',\n removed: '已删除 {item}',\n unknownType: '没有注册类型为 {type} 的格子',\n loading: '加载中',\n error: '加载失败',\n renderError: '无法显示',\n settingsError: '无法显示设置',\n empty: '暂无数据',\n retry: '重试',\n emptyTitle: '还没有格子',\n emptyHint: '从列表里拖进来,或点一下添加',\n palette: '添加格子',\n paletteItem: '添加{label}',\n filteredBy: '已按 {value} 筛选',\n peerMoving: '{name} 正在移动',\n peerResizing: '{name} 正在调整大小',\n peerSettings: '{name} 正在修改设置',\n clearFilter: '清除筛选:{value}',\n filterBar: '筛选',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除筛选',\n source: '数据源',\n noSource: '不使用数据源',\n field: '字段',\n value: '数值',\n prefix: '前缀',\n suffix: '后缀',\n precision: '小数位数',\n trend: '迷你图字段',\n delta: '变化率字段',\n deltaText: '较上期 {value}',\n text: '文字',\n textSize: '字号',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '列',\n columnTitle: '{field} 的标题',\n chartKind: '图表',\n chartLine: '折线图',\n chartArea: '面积图',\n chartBar: '柱状图',\n chartPie: '饼图',\n xField: '分类或时间',\n yFields: '数值',\n stacked: '堆叠',\n horizontal: '横向',\n chartFilter: '点击时筛选',\n chartFilterHint: '点图表里的一项时,用这个名字筛选其他格子;留空则不筛选',\n pivotFilter: '点击单元格时,按它所在的分组筛选其他格子',\n}\n\nconst zhTW: DashboardMessages = {\n layout: '網格版面',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向鍵移動、Shift 加方向鍵調整大小',\n locked: '{item} 已鎖定,無法移動',\n position: '第 {x} 欄第 {y} 列,寬 {w} 欄,高 {h} 列',\n order: '第 {n} 個,共 {count} 個',\n grabbed: '已拿起 {item},{position}。方向鍵移動,Shift 加方向鍵調整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原處',\n resize: '調整大小',\n dashboard: '儀表板',\n widgetMenu: '格子操作',\n settings: '設定',\n fullscreen: '全螢幕檢視',\n export: '匯出',\n exportFailed: '無法匯出 {name}:{reason}',\n exported: '已匯出 {name}',\n nothingToExport: '沒有可匯出的資料',\n duplicate: '複製一份',\n remove: '刪除',\n comment: '評論',\n comments: '{count} 則評論',\n settingsTitle: '{title}的設定',\n titleField: '標題',\n added: '已新增 {item}',\n removed: '已刪除 {item}',\n unknownType: '沒有註冊類型為 {type} 的格子',\n loading: '載入中',\n error: '載入失敗',\n renderError: '無法顯示',\n settingsError: '無法顯示設定',\n empty: '暫無資料',\n retry: '重試',\n emptyTitle: '還沒有格子',\n emptyHint: '從清單拖進來,或點一下新增',\n palette: '新增格子',\n paletteItem: '新增{label}',\n filteredBy: '已按 {value} 篩選',\n peerMoving: '{name} 正在移動',\n peerResizing: '{name} 正在調整大小',\n peerSettings: '{name} 正在修改設定',\n clearFilter: '清除篩選:{value}',\n filterBar: '篩選',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除篩選',\n source: '資料來源',\n noSource: '不使用資料來源',\n field: '欄位',\n value: '數值',\n prefix: '前綴',\n suffix: '後綴',\n precision: '小數位數',\n trend: '迷你圖欄位',\n delta: '變化率欄位',\n deltaText: '較上期 {value}',\n text: '文字',\n textSize: '字號',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '欄',\n columnTitle: '{field} 的標題',\n chartKind: '圖表',\n chartLine: '折線圖',\n chartArea: '面積圖',\n chartBar: '長條圖',\n chartPie: '圓餅圖',\n xField: '分類或時間',\n yFields: '數值',\n stacked: '堆疊',\n horizontal: '橫向',\n chartFilter: '點擊時篩選',\n chartFilterHint: '點圖表裡的一項時,用這個名字篩選其他格子;留空則不篩選',\n pivotFilter: '點擊儲存格時,依其所在的分組篩選其他格子',\n}\n\nconst en: DashboardMessages = {\n layout: 'Grid layout',\n item: 'tile',\n itemHint: 'Press Enter to pick up, then arrow keys to move and Shift with arrow keys to resize',\n locked: '{item} is locked and can’t be moved',\n position: 'column {x}, row {y}, {w} columns wide, {h} rows high',\n order: '{n} of {count}',\n grabbed:\n 'Picked up {item}, {position}. Arrow keys move, Shift with arrow keys resizes, Enter puts down, Escape cancels',\n dropped: 'Put down {item}, {position}',\n cancelled: 'Cancelled, {item} is back where it was',\n resize: 'Resize',\n dashboard: 'Dashboard',\n widgetMenu: 'Widget actions',\n settings: 'Settings',\n fullscreen: 'View full screen',\n export: 'Export',\n exportFailed: \"Couldn't export {name}: {reason}\",\n exported: 'Exported {name}',\n nothingToExport: 'There is no data to export',\n duplicate: 'Duplicate',\n remove: 'Remove',\n comment: 'Comment',\n comments: '{count} comments',\n settingsTitle: '{title} settings',\n titleField: 'Title',\n added: 'Added {item}',\n removed: 'Removed {item}',\n unknownType: 'No widget type “{type}” is registered',\n loading: 'Loading',\n error: 'Couldn’t load',\n renderError: 'Couldn’t display',\n settingsError: 'Couldn’t display the settings',\n empty: 'No data',\n retry: 'Retry',\n emptyTitle: 'No widgets yet',\n emptyHint: 'Drag one in from the list, or click to add it',\n palette: 'Add widget',\n paletteItem: 'Add {label}',\n filteredBy: 'Filtered by {value}',\n peerMoving: '{name} is moving it',\n peerResizing: '{name} is resizing it',\n peerSettings: '{name} is changing its settings',\n clearFilter: 'Clear filter: {value}',\n filterBar: 'Filters',\n linkedFilter: '{title}: {value}',\n clearFilters: 'Clear filters',\n source: 'Source',\n noSource: 'No source',\n field: 'Field',\n value: 'Value',\n prefix: 'Prefix',\n suffix: 'Suffix',\n precision: 'Decimal places',\n trend: 'Sparkline field',\n delta: 'Change field',\n deltaText: '{value} vs. last period',\n text: 'Text',\n textSize: 'Size',\n sizeSmall: 'Small',\n sizeMedium: 'Medium',\n sizeLarge: 'Large',\n columns: 'Columns',\n columnTitle: 'Title of {field}',\n chartKind: 'Chart',\n chartLine: 'Line',\n chartArea: 'Area',\n chartBar: 'Bar',\n chartPie: 'Pie',\n xField: 'Category or time',\n yFields: 'Values',\n stacked: 'Stacked',\n horizontal: 'Horizontal',\n chartFilter: 'Filter on click',\n chartFilterHint:\n 'Clicking an item filters the other widgets by this name; leave empty to not filter',\n pivotFilter: 'Clicking a cell filters the other widgets by its groups',\n}\n\nexport const dashboardLocales: Record<string, DashboardMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type DashboardMessagesOverride = Partial<DashboardMessages>\n\n/**\n * The dashboard's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useDashboardMessages(\n override?: MaybeRefOrGetter<DashboardMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<DashboardMessages>(() => {\n const name = locale.value.name\n const base =\n dashboardLocales[name] ??\n dashboardLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pivot-settings.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivotFields } from '@dou-ui/pivot'\nimport type { PivotField } from '@dou-ui/pivot'\nimport { DouSwitch } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from '../widgets/settings-field.vue'\nimport { rowsOf } from '../widgets/shared'\nimport SourceField from '../widgets/source-field.vue'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotSettings' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\nconst model = defineModel<PivotWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst rows = computed(() => rowsOf(data.value, model.value.path))\nconst set = (patch: Partial<PivotWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField :model-value=\"model.source\" @update:model-value=\"(source) => set({ source })\" />\n <SettingsField v-if=\"rows.length\" :label=\"messages.field\">\n <DouPivotFields\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"model.config\"\n :drawer=\"false\"\n @update:config=\"(config) => set({ config })\"\n />\n </SettingsField>\n <DouSwitch\n :model-value=\"!!model.filter\"\n @update:model-value=\"(filter) => set({ filter: filter || undefined })\"\n >\n {{ messages.pivotFilter }}\n </DouSwitch>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"pivot-settings.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivotFields } from '@dou-ui/pivot'\nimport type { PivotField } from '@dou-ui/pivot'\nimport { DouSwitch } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from '../widgets/settings-field.vue'\nimport { rowsOf } from '../widgets/shared'\nimport SourceField from '../widgets/source-field.vue'\nimport type { PivotWidgetProps } from './types'\nimport { pivotPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardPivotSettings' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\nconst model = defineModel<PivotWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => pivotPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst rows = computed(() => rowsOf(data.value, view.value.path))\nconst set = (patch: Partial<PivotWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField :model-value=\"view.source\" @update:model-value=\"(source) => set({ source })\" />\n <SettingsField v-if=\"rows.length\" :label=\"messages.field\">\n <DouPivotFields\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"view.config\"\n :drawer=\"false\"\n @update:config=\"(config) => set({ config })\"\n />\n </SettingsField>\n <DouSwitch\n :model-value=\"!!view.filter\"\n @update:model-value=\"(filter) => set({ filter: filter || undefined })\"\n >\n {{ messages.pivotFilter }}\n </DouSwitch>\n </div>\n</template>\n"],"mappings":""}
@@ -3,6 +3,7 @@ import { useDashboardWidget } from "../widget/context.js";
3
3
  import { rowsOf } from "../widgets/shared.js";
4
4
  import settings_field_default from "../widgets/settings-field.js";
5
5
  import source_field_default from "../widgets/source-field.js";
6
+ import { pivotPropsOf } from "./read-props.js";
6
7
  import { DouSwitch } from "dou-ui";
7
8
  import { computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, createVNode, defineComponent, mergeModels, openBlock, toDisplayString, unref, useModel, withCtx } from "vue";
8
9
  import { DouPivotFields } from "@dou-ui/pivot";
@@ -18,9 +19,10 @@ var pivot_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(() => pivotPropsOf(model.value));
21
23
  const messages = useDashboardMessages();
22
24
  const { data } = useDashboardWidget();
23
- const rows = computed(() => rowsOf(data.value, model.value.path));
25
+ const rows = computed(() => rowsOf(data.value, view.value.path));
24
26
  const set = (patch) => model.value = {
25
27
  ...model.value,
26
28
  ...patch
@@ -28,7 +30,7 @@ var pivot_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
28
30
  return (_ctx, _cache) => {
29
31
  return openBlock(), createElementBlock("div", _hoisted_1, [
30
32
  createVNode(source_field_default, {
31
- "model-value": model.value.source,
33
+ "model-value": view.value.source,
32
34
  "onUpdate:modelValue": _cache[0] || (_cache[0] = (source) => set({ source }))
33
35
  }, null, 8, ["model-value"]),
34
36
  rows.value.length ? (openBlock(), createBlock(settings_field_default, {
@@ -38,7 +40,7 @@ var pivot_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
38
40
  default: withCtx(() => [createVNode(unref(DouPivotFields), {
39
41
  data: rows.value,
40
42
  fields: __props.fields,
41
- config: model.value.config,
43
+ config: view.value.config,
42
44
  drawer: false,
43
45
  "onUpdate:config": _cache[1] || (_cache[1] = (config) => set({ config }))
44
46
  }, null, 8, [
@@ -49,7 +51,7 @@ var pivot_settings_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
49
51
  _: 1
50
52
  }, 8, ["label"])) : createCommentVNode("", true),
51
53
  createVNode(unref(DouSwitch), {
52
- "model-value": !!model.value.filter,
54
+ "model-value": !!view.value.filter,
53
55
  "onUpdate:modelValue": _cache[2] || (_cache[2] = (filter) => set({ filter: filter || void 0 }))
54
56
  }, {
55
57
  default: withCtx(() => [createTextVNode(toDisplayString(unref(messages).pivotFilter), 1)]),
@@ -1 +1 @@
1
- {"version":3,"file":"pivot-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SourceField","_createBlock","SettingsField","_unref","_withCtx","_createCommentVNode","_createTextVNode","_toDisplayString"],"sources":["../../src/pivot/pivot-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivotFields } from '@dou-ui/pivot'\nimport type { PivotField } from '@dou-ui/pivot'\nimport { DouSwitch } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from '../widgets/settings-field.vue'\nimport { rowsOf } from '../widgets/shared'\nimport SourceField from '../widgets/source-field.vue'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotSettings' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\nconst model = defineModel<PivotWidgetProps>({ required: true })\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst rows = computed(() => rowsOf(data.value, model.value.path))\nconst set = (patch: Partial<PivotWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField :model-value=\"model.source\" @update:model-value=\"(source) => set({ source })\" />\n <SettingsField v-if=\"rows.length\" :label=\"messages.field\">\n <DouPivotFields\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"model.config\"\n :drawer=\"false\"\n @update:config=\"(config) => set({ config })\"\n />\n </SettingsField>\n <DouSwitch\n :model-value=\"!!model.filter\"\n @update:model-value=\"(filter) => set({ filter: filter || undefined })\"\n >\n {{ messages.pivotFilter }}\n </DouSwitch>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAeA,MAAM,QAAQA,SAA6B,SAAA,YAAmB;EAC9D,MAAM,WAAW,qBAAqB;EACtC,MAAM,EAAE,SAAS,mBAAmB;EACpC,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;EAChE,MAAM,OAAO,UAAsC,MAAM,QAAQ;GAAE,GAAG,MAAM;GAAO,GAAG;EAAM;;GAI1F,OAAAC,UAAA,GAAAC,mBAiBM,OAjBN,YAiBM;IAhBJC,YAA6FC,sBAAA;KAA/E,eAAa,MAAA,MAAM;KAAS,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAG,OAAM,CAAA;;IACjE,KAAA,MAAK,UAA1BH,UAAA,GAAAI,YAQgBC,wBAAA;;KARmB,OAAOC,MAAA,QAAA,CAAQ,CAAC;;KACjD,SAAAC,cAME,CANFL,YAMEI,MAAA,cAAA,GAAA;MALC,MAAM,KAAA;MACN,QAAQ,QAAA;MACR,QAAQ,MAAA,MAAM;MACd,QAAQ;MACR,mBAAa,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAG,OAAM,CAAA;;;;;;;;IAG5CJ,YAKYI,MAAA,SAAA,GAAA;KAJT,eAAW,CAAA,CAAI,MAAA,MAAM;KACrB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAA,QAAW,UAAU,KAAA,EAAS,CAAA;;KAElE,SAAAC,cAA0B,CAAvBE,gBAAAC,gBAAAJ,MAAA,QAAA,CAAQ,CAAC,WAAW,GAAA,CAAA,C"}
1
+ {"version":3,"file":"pivot-settings.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_createVNode","SourceField","_createBlock","SettingsField","_unref","_withCtx","_createCommentVNode","_createTextVNode","_toDisplayString"],"sources":["../../src/pivot/pivot-settings.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivotFields } from '@dou-ui/pivot'\nimport type { PivotField } from '@dou-ui/pivot'\nimport { DouSwitch } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useDashboardMessages } from '../locale'\nimport { useDashboardWidget } from '../widget/context'\nimport SettingsField from '../widgets/settings-field.vue'\nimport { rowsOf } from '../widgets/shared'\nimport SourceField from '../widgets/source-field.vue'\nimport type { PivotWidgetProps } from './types'\nimport { pivotPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardPivotSettings' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\nconst model = defineModel<PivotWidgetProps>({ required: true })\n// the props as saved may have the wrong types: read them as the widget does\nconst view = computed(() => pivotPropsOf(model.value as Record<string, unknown>))\nconst messages = useDashboardMessages()\nconst { data } = useDashboardWidget()\nconst rows = computed(() => rowsOf(data.value, view.value.path))\nconst set = (patch: Partial<PivotWidgetProps>) => (model.value = { ...model.value, ...patch })\n</script>\n\n<template>\n <div class=\"dou-dashboard__settings\">\n <SourceField :model-value=\"view.source\" @update:model-value=\"(source) => set({ source })\" />\n <SettingsField v-if=\"rows.length\" :label=\"messages.field\">\n <DouPivotFields\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"view.config\"\n :drawer=\"false\"\n @update:config=\"(config) => set({ config })\"\n />\n </SettingsField>\n <DouSwitch\n :model-value=\"!!view.filter\"\n @update:model-value=\"(filter) => set({ filter: filter || undefined })\"\n >\n {{ messages.pivotFilter }}\n </DouSwitch>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAgBA,MAAM,QAAQA,SAA6B,SAAA,YAAmB;EAE9D,MAAM,OAAO,eAAe,aAAa,MAAM,KAAgC,CAAC;EAChF,MAAM,WAAW,qBAAqB;EACtC,MAAM,EAAE,SAAS,mBAAmB;EACpC,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,KAAK,MAAM,IAAI,CAAC;EAC/D,MAAM,OAAO,UAAsC,MAAM,QAAQ;GAAE,GAAG,MAAM;GAAO,GAAG;EAAM;;GAI1F,OAAAC,UAAA,GAAAC,mBAiBM,OAjBN,YAiBM;IAhBJC,YAA4FC,sBAAA;KAA9E,eAAa,KAAA,MAAK;KAAS,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAG,OAAM,CAAA;;IAChE,KAAA,MAAK,UAA1BH,UAAA,GAAAI,YAQgBC,wBAAA;;KARmB,OAAOC,MAAA,QAAA,CAAQ,CAAC;;KACjD,SAAAC,cAME,CANFL,YAMEI,MAAA,cAAA,GAAA;MALC,MAAM,KAAA;MACN,QAAQ,QAAA;MACR,QAAQ,KAAA,MAAK;MACb,QAAQ;MACR,mBAAa,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAG,OAAM,CAAA;;;;;;;;IAG5CJ,YAKYI,MAAA,SAAA,GAAA;KAJT,eAAW,CAAA,CAAI,KAAA,MAAK;KACpB,uBAAkB,OAAA,OAAA,OAAA,MAAG,WAAW,IAAG,EAAA,QAAW,UAAU,KAAA,EAAS,CAAA;;KAElE,SAAAC,cAA0B,CAAvBE,gBAAAC,gBAAAJ,MAAA,QAAA,CAAQ,CAAC,WAAW,GAAA,CAAA,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"pivot.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } =\n useDashboardWidget<PivotWidgetProps>()\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\nwatch(\n () => props.value.config,\n (next) => (config.value = next),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :bordered=\"false\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"pivot.js","names":["_sfc_main"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport { pivotPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst {\n props: raw,\n data,\n size,\n setFilter,\n ownFilters,\n editing,\n setProps,\n setWorkbook,\n} = useDashboardWidget()\nconst props = computed(() => pivotPropsOf(raw.value))\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\n// only a new config from the props replaces it, not a change to another prop\nwatch(\n () => raw.value.config,\n () => (config.value = props.value.config),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :bordered=\"false\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":""}
@@ -1,5 +1,6 @@
1
1
  import { useDashboardWidget } from "../widget/context.js";
2
2
  import { filterValueOf, rowsOf } from "../widgets/shared.js";
3
+ import { pivotPropsOf } from "./read-props.js";
3
4
  import { computed, createBlock, defineComponent, openBlock, shallowRef, unref, watch } from "vue";
4
5
  import { DouPivot } from "@dou-ui/pivot";
5
6
  // src/pivot/pivot.vue?vue&type=script&setup=true&lang.ts
@@ -8,12 +9,13 @@ var pivot_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
8
9
  __name: "pivot",
9
10
  props: { fields: {} },
10
11
  setup(__props) {
11
- const { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } = useDashboardWidget();
12
+ const { props: raw, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } = useDashboardWidget();
13
+ const props = computed(() => pivotPropsOf(raw.value));
12
14
  const pivot = shallowRef();
13
15
  setWorkbook(() => pivot.value?.toSheet({ name: "" }));
14
16
  const rows = computed(() => rowsOf(data.value, props.value.path));
15
17
  const config = shallowRef(props.value.config);
16
- watch(() => props.value.config, (next) => config.value = next);
18
+ watch(() => raw.value.config, () => config.value = props.value.config);
17
19
  function onConfig(next) {
18
20
  config.value = next;
19
21
  if (editing.value) setProps({ config: next }, { group: "pivot-config" });
@@ -1 +1 @@
1
- {"version":3,"file":"pivot.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst { props, data, size, setFilter, ownFilters, editing, setProps, setWorkbook } =\n useDashboardWidget<PivotWidgetProps>()\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\nwatch(\n () => props.value.config,\n (next) => (config.value = next),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :bordered=\"false\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":";;;;;;;;;;EAkBA,MAAM,EAAE,OAAO,MAAM,MAAM,WAAW,YAAY,SAAS,UAAU,gBACnE,mBAAqC;EACvC,MAAM,QAAQ,WAAwB;EAEtC,kBAAkB,MAAM,OAAO,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;EACpD,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;EAEhE,MAAM,SAAS,WAAoC,MAAM,MAAM,MAAM;EACrE,YACQ,MAAM,MAAM,SACjB,SAAU,OAAO,QAAQ,IAC5B;EACA,SAAS,SAAS,MAAmB;GACnC,OAAO,QAAQ;GACf,IAAI,QAAQ,OAAO,SAAS,EAAE,QAAQ,KAAK,GAAG,EAAE,OAAO,eAAe,CAAC;EACzE;EACA,MAAM,UAAU,cACd,OAAO,cAAc,WAAW,YAAY,UAAU;;EAGxD,SAAS,OAAO,aAAwC,CAAC,GAAG,SAAkC;GAC5F,MAAM,OAAkB,CAAC;GACzB,KAAK,MAAM,aAAa,YAAY;IAClC,MAAM,QAAQ,QAAQ,OAAO,SAAS;IACtC,IAAI,UAAU,KAAA,GAAW;IACzB,KAAK,KAAK,KAAK;GACjB;GACA,OAAO;EACT;EACA,MAAM,YAAY,eAAe;GAC/B,IAAI,CAAC,MAAM,MAAM,QAAQ,OAAO,KAAA;GAChC,MAAM,UAAU,WAAW;GAC3B,OAAO;IACL,KAAK,OAAO,OAAO,OAAO,MAAM,OAAO;IACvC,QAAQ,OAAO,OAAO,OAAO,SAAS,OAAO;GAC/C;EACF,CAAC;;EAGD,SAAS,MACP,aAAwC,CAAC,GACzC,MACA,QACA;GACA,WAAW,SAAS,WAAW,MAC7B,IAAI,KAAK,SACL,UAAU,OAAO,SAAS,GAAG,cAAc,KAAK,EAAE,GAAG,EAAE,OAAO,OAAO,GAAG,CAAC,IACzE,UAAU,OAAO,SAAS,GAAG,KAAA,CAAS,CAC5C;EACF;;EAGA,SAAS,OAAO,MAAsB;GACpC,IAAI,CAAC,MAAM,MAAM,QAAQ;GACzB,MAAM,EAAE,MAAM,SAAS,SAAS,eAAe,OAAO,SAAS,CAAC;GAChE,MAAM,SAAS,KAAK,KAAK,KAAK,OAAO,GAAG;GACxC,MAAM,YAAY,KAAK,QAAQ,KAAK,OAAO,MAAM;EACnD;;GAIE,OAAAA,UAAA,GAAAC,YAYEC,MAAA,QAAA,GAAA;IAXI,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,UAAU;IACV,MAAM,KAAA;IACN,QAAQ,QAAA;IACR,QAAQ,OAAA;IACR,WAAW,UAAA;IACZ,MAAK;IACJ,cAAYA,MAAA,IAAA,CAAI,CAAC,OAAO,SAAS,KAAA;IACjC,mBAAe;IACf,aAAY"}
1
+ {"version":3,"file":"pivot.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_unref"],"sources":["../../src/pivot/pivot.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouPivot } from '@dou-ui/pivot'\nimport type {\n PivotCellEvent,\n PivotConfig,\n PivotDimension,\n PivotExpose,\n PivotField,\n} from '@dou-ui/pivot'\nimport { computed, shallowRef, watch } from 'vue'\nimport { useDashboardWidget } from '../widget/context'\nimport { filterValueOf, rowsOf } from '../widgets/shared'\nimport { pivotPropsOf } from './read-props'\n\ndefineOptions({ name: 'DouDashboardPivotWidget' })\n\ndefineProps<{ fields?: readonly PivotField[] }>()\n\nconst {\n props: raw,\n data,\n size,\n setFilter,\n ownFilters,\n editing,\n setProps,\n setWorkbook,\n} = useDashboardWidget()\nconst props = computed(() => pivotPropsOf(raw.value))\nconst pivot = shallowRef<PivotExpose>()\n// the export menu writes the table as it shows: merged heads, totals, number formats\nsetWorkbook(() => pivot.value?.toSheet({ name: '' }))\nconst rows = computed(() => rowsOf(data.value, props.value.path))\n// sorting in the table works while viewing too; only while editing is it saved\nconst config = shallowRef<PivotConfig | undefined>(props.value.config)\n// only a new config from the props replaces it, not a change to another prop\nwatch(\n () => raw.value.config,\n () => (config.value = props.value.config),\n)\nfunction onConfig(next: PivotConfig) {\n config.value = next\n if (editing.value) setProps({ config: next }, { group: 'pivot-config' })\n}\nconst nameOf = (dimension: PivotDimension) =>\n typeof dimension === 'string' ? dimension : dimension.field\n\n/** The groups this widget's filters picked, marked in the table. */\nfunction pathOf(dimensions: readonly PivotDimension[] = [], filters: Record<string, unknown>) {\n const path: unknown[] = []\n for (const dimension of dimensions) {\n const value = filters[nameOf(dimension)]\n if (value === undefined) break\n path.push(value)\n }\n return path\n}\nconst highlight = computed(() => {\n if (!props.value.filter) return undefined\n const filters = ownFilters.value\n return {\n row: pathOf(config.value?.rows, filters),\n column: pathOf(config.value?.columns, filters),\n }\n})\n\n/** One filter per field of a group's path; the fields past its end are cleared. */\nfunction apply(\n dimensions: readonly PivotDimension[] = [],\n path: readonly unknown[],\n labels: string[],\n) {\n dimensions.forEach((dimension, i) =>\n i < path.length\n ? setFilter(nameOf(dimension), filterValueOf(path[i]), { label: labels[i] })\n : setFilter(nameOf(dimension), undefined),\n )\n}\n\n/** Sets one filter per field of the clicked cell's groups; a total clears the deeper ones. */\nfunction onCell(cell: PivotCellEvent) {\n if (!props.value.filter) return\n const { rows: rowDims, columns: columnDims } = config.value ?? {}\n apply(rowDims, cell.row, cell.labels.row)\n apply(columnDims, cell.column, cell.labels.column)\n}\n</script>\n\n<template>\n <DouPivot\n ref=\"pivot\"\n class=\"dou-dashboard-pivot\"\n :bordered=\"false\"\n :data=\"rows\"\n :fields=\"fields\"\n :config=\"config\"\n :highlight=\"highlight\"\n size=\"sm\"\n :max-height=\"size.height.value || undefined\"\n @update:config=\"onConfig\"\n @cell-click=\"onCell\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;EAkBA,MAAM,EACJ,OAAO,KACP,MACA,MACA,WACA,YACA,SACA,UACA,gBACE,mBAAmB;EACvB,MAAM,QAAQ,eAAe,aAAa,IAAI,KAAK,CAAC;EACpD,MAAM,QAAQ,WAAwB;EAEtC,kBAAkB,MAAM,OAAO,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;EACpD,MAAM,OAAO,eAAe,OAAO,KAAK,OAAO,MAAM,MAAM,IAAI,CAAC;EAEhE,MAAM,SAAS,WAAoC,MAAM,MAAM,MAAM;EAErE,YACQ,IAAI,MAAM,cACT,OAAO,QAAQ,MAAM,MAAM,MACpC;EACA,SAAS,SAAS,MAAmB;GACnC,OAAO,QAAQ;GACf,IAAI,QAAQ,OAAO,SAAS,EAAE,QAAQ,KAAK,GAAG,EAAE,OAAO,eAAe,CAAC;EACzE;EACA,MAAM,UAAU,cACd,OAAO,cAAc,WAAW,YAAY,UAAU;;EAGxD,SAAS,OAAO,aAAwC,CAAC,GAAG,SAAkC;GAC5F,MAAM,OAAkB,CAAC;GACzB,KAAK,MAAM,aAAa,YAAY;IAClC,MAAM,QAAQ,QAAQ,OAAO,SAAS;IACtC,IAAI,UAAU,KAAA,GAAW;IACzB,KAAK,KAAK,KAAK;GACjB;GACA,OAAO;EACT;EACA,MAAM,YAAY,eAAe;GAC/B,IAAI,CAAC,MAAM,MAAM,QAAQ,OAAO,KAAA;GAChC,MAAM,UAAU,WAAW;GAC3B,OAAO;IACL,KAAK,OAAO,OAAO,OAAO,MAAM,OAAO;IACvC,QAAQ,OAAO,OAAO,OAAO,SAAS,OAAO;GAC/C;EACF,CAAC;;EAGD,SAAS,MACP,aAAwC,CAAC,GACzC,MACA,QACA;GACA,WAAW,SAAS,WAAW,MAC7B,IAAI,KAAK,SACL,UAAU,OAAO,SAAS,GAAG,cAAc,KAAK,EAAE,GAAG,EAAE,OAAO,OAAO,GAAG,CAAC,IACzE,UAAU,OAAO,SAAS,GAAG,KAAA,CAAS,CAC5C;EACF;;EAGA,SAAS,OAAO,MAAsB;GACpC,IAAI,CAAC,MAAM,MAAM,QAAQ;GACzB,MAAM,EAAE,MAAM,SAAS,SAAS,eAAe,OAAO,SAAS,CAAC;GAChE,MAAM,SAAS,KAAK,KAAK,KAAK,OAAO,GAAG;GACxC,MAAM,YAAY,KAAK,QAAQ,KAAK,OAAO,MAAM;EACnD;;GAIE,OAAAA,UAAA,GAAAC,YAYEC,MAAA,QAAA,GAAA;IAXI,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,UAAU;IACV,MAAM,KAAA;IACN,QAAQ,QAAA;IACR,QAAQ,OAAA;IACR,WAAW,UAAA;IACZ,MAAK;IACJ,cAAYA,MAAA,IAAA,CAAI,CAAC,OAAO,SAAS,KAAA;IACjC,mBAAe;IACf,aAAY"}
@@ -0,0 +1,44 @@
1
+ import { flagOf, oneOf, recordOf, textOf } from "../widgets/shared.js";
2
+ // src/pivot/read-props.ts
3
+ /** A field on the rows or columns: its name, or an object with a text `field`. */
4
+ var isDimension = (item) => typeof item === "string" || typeof recordOf(item)?.field === "string";
5
+ /** A value: a field's name, or an object. */
6
+ var isValue = (item) => typeof item === "string" || recordOf(item) !== void 0;
7
+ var listOf = (value, keep) => Array.isArray(value) ? value.filter(keep) : void 0;
8
+ /**
9
+ * The pivot's config with the right shape at its top: lists where lists go,
10
+ * objects where objects go; what isn't counts as not set. Deeper mistakes,
11
+ * like a filter's `include` that isn't a list, are left to the widget's
12
+ * error state.
13
+ */
14
+ function configOf(value) {
15
+ const config = recordOf(value);
16
+ if (!config) return void 0;
17
+ const filters = recordOf(config.filters);
18
+ const sort = recordOf(config.sort);
19
+ const totals = recordOf(config.totals);
20
+ return {
21
+ rows: listOf(config.rows, isDimension),
22
+ columns: listOf(config.columns, isDimension),
23
+ values: listOf(config.values, isValue),
24
+ filters: filters ? Object.fromEntries(Object.entries(filters).filter(([, filter]) => recordOf(filter))) : void 0,
25
+ valuesOn: oneOf(config.valuesOn, ["columns", "rows"]),
26
+ sort: sort && typeof sort.valueIndex === "number" && oneOf(sort.order, ["asc", "desc"]) ? sort : void 0,
27
+ totals: totals ? {
28
+ ...typeof totals.rows === "boolean" ? { rows: totals.rows } : {},
29
+ ...typeof totals.columns === "boolean" ? { columns: totals.columns } : {}
30
+ } : void 0
31
+ };
32
+ }
33
+ /** The pivot widget's props as its type says; what isn't the right type counts as not set. */
34
+ function pivotPropsOf(props) {
35
+ return {
36
+ source: textOf(props.source),
37
+ path: textOf(props.path),
38
+ config: configOf(props.config),
39
+ filter: flagOf(props.filter)
40
+ };
41
+ }
42
+ export { pivotPropsOf };
43
+
44
+ //# sourceMappingURL=read-props.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-props.js","names":[],"sources":["../../src/pivot/read-props.ts"],"sourcesContent":["import type { PivotConfig, PivotDimension, PivotValue } from '@dou-ui/pivot'\nimport { flagOf, oneOf, recordOf, textOf } from '../widgets/shared'\nimport type { PivotWidgetProps } from './types'\n\n/** A field on the rows or columns: its name, or an object with a text `field`. */\nconst isDimension = (item: unknown): item is PivotDimension =>\n typeof item === 'string' || typeof recordOf(item)?.field === 'string'\n\n/** A value: a field's name, or an object. */\nconst isValue = (item: unknown): item is PivotValue =>\n typeof item === 'string' || recordOf(item) !== undefined\n\nconst listOf = <T>(value: unknown, keep: (item: unknown) => item is T): T[] | undefined =>\n Array.isArray(value) ? value.filter(keep) : undefined\n\n/**\n * The pivot's config with the right shape at its top: lists where lists go,\n * objects where objects go; what isn't counts as not set. Deeper mistakes,\n * like a filter's `include` that isn't a list, are left to the widget's\n * error state.\n */\nfunction configOf(value: unknown): PivotConfig | undefined {\n const config = recordOf(value)\n if (!config) return undefined\n const filters = recordOf(config.filters)\n const sort = recordOf(config.sort)\n const totals = recordOf(config.totals)\n return {\n rows: listOf(config.rows, isDimension),\n columns: listOf(config.columns, isDimension),\n values: listOf(config.values, isValue),\n filters: filters\n ? (Object.fromEntries(\n Object.entries(filters).filter(([, filter]) => recordOf(filter)),\n ) as PivotConfig['filters'])\n : undefined,\n valuesOn: oneOf(config.valuesOn, ['columns', 'rows'] as const),\n sort:\n sort && typeof sort.valueIndex === 'number' && oneOf(sort.order, ['asc', 'desc'] as const)\n ? (sort as unknown as PivotConfig['sort'])\n : undefined,\n totals: totals\n ? {\n ...(typeof totals.rows === 'boolean' ? { rows: totals.rows } : {}),\n ...(typeof totals.columns === 'boolean' ? { columns: totals.columns } : {}),\n }\n : undefined,\n }\n}\n\n/** The pivot widget's props as its type says; what isn't the right type counts as not set. */\nexport function pivotPropsOf(props: Record<string, unknown>): PivotWidgetProps {\n return {\n source: textOf(props.source),\n path: textOf(props.path),\n config: configOf(props.config),\n filter: flagOf(props.filter),\n }\n}\n"],"mappings":";;;AAKA,IAAM,eAAe,SACnB,OAAO,SAAS,YAAY,OAAO,SAAS,IAAI,CAAC,EAAE,UAAU;;AAG/D,IAAM,WAAW,SACf,OAAO,SAAS,YAAY,SAAS,IAAI,MAAM,KAAA;AAEjD,IAAM,UAAa,OAAgB,SACjC,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,IAAI,IAAI,KAAA;;;;;;;AAQ9C,SAAS,SAAS,OAAyC;CACzD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,MAAM,UAAU,SAAS,OAAO,OAAO;CACvC,MAAM,OAAO,SAAS,OAAO,IAAI;CACjC,MAAM,SAAS,SAAS,OAAO,MAAM;CACrC,OAAO;EACL,MAAM,OAAO,OAAO,MAAM,WAAW;EACrC,SAAS,OAAO,OAAO,SAAS,WAAW;EAC3C,QAAQ,OAAO,OAAO,QAAQ,OAAO;EACrC,SAAS,UACJ,OAAO,YACN,OAAO,QAAQ,OAAO,CAAC,CAAC,QAAQ,GAAG,YAAY,SAAS,MAAM,CAAC,CACjE,IACA,KAAA;EACJ,UAAU,MAAM,OAAO,UAAU,CAAC,WAAW,MAAM,CAAU;EAC7D,MACE,QAAQ,OAAO,KAAK,eAAe,YAAY,MAAM,KAAK,OAAO,CAAC,OAAO,MAAM,CAAU,IACpF,OACD,KAAA;EACN,QAAQ,SACJ;GACE,GAAI,OAAO,OAAO,SAAS,YAAY,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;GAChE,GAAI,OAAO,OAAO,YAAY,YAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EAC3E,IACA,KAAA;CACN;AACF;;AAGA,SAAgB,aAAa,OAAkD;CAC7E,OAAO;EACL,QAAQ,OAAO,MAAM,MAAM;EAC3B,MAAM,OAAO,MAAM,IAAI;EACvB,QAAQ,SAAS,MAAM,MAAM;EAC7B,QAAQ,OAAO,MAAM,MAAM;CAC7B;AACF"}
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- @layer dou.components{.dou-grid-layout{--dou-grid-item-radius:var(--dou-radius-container);--dou-grid-col:calc((100cqw - (var(--dou-grid-columns) - 1)*var(--dou-grid-gap-x))/var(--dou-grid-columns));position:relative;box-sizing:border-box;height:calc(var(--dou-grid-rows)*var(--dou-grid-row) + max(var(--dou-grid-rows) - 1,0)*var(--dou-grid-gap-y));container-type:inline-size;width:100%;min-width:0}.dou-grid-layout.is-pointer-dragging{cursor:grabbing}.dou-grid-layout.is-resizing{cursor:nwse-resize}.dou-grid-layout__item,.dou-grid-layout__placeholder{position:absolute;box-sizing:border-box;width:calc(var(--dou-grid-w)*var(--dou-grid-col) + (var(--dou-grid-w) - 1)*var(--dou-grid-gap-x) + var(--dou-grid-dw,0px));height:calc(var(--dou-grid-h)*var(--dou-grid-row) + (var(--dou-grid-h) - 1)*var(--dou-grid-gap-y) + var(--dou-grid-dh,0px));border-radius:var(--dou-grid-item-radius);transform:translate(calc(var(--dou-grid-x)*(var(--dou-grid-col) + var(--dou-grid-gap-x)) + var(--dou-grid-dx,0px)),calc(var(--dou-grid-y)*(var(--dou-grid-row) + var(--dou-grid-gap-y)) + var(--dou-grid-dy,0px)));top:0;left:0}.dou-grid-layout__item{display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);outline:none;min-width:0}.dou-grid-layout__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-grid-layout.is-editable .dou-grid-layout__item.is-movable{user-select:none;-webkit-touch-callout:none}.dou-grid-layout.is-editable:not(:-webkit-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:-moz-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:is(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-arranging .dou-grid-layout__item{transition:transform var(--dou-motion-duration-normal)var(--dou-motion-easing)}.dou-grid-layout__item.is-dragging,.dou-grid-layout__item.is-resizing{z-index:2;box-shadow:var(--dou-shadow-lg)}.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-dragging,.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-resizing{transition:none}.dou-grid-layout__placeholder{z-index:1;border:1px dashed var(--dou-color-border-strong);background-color:color-mix(in oklab,var(--dou-color-text)4%,transparent);pointer-events:none}.dou-grid-layout.is-arranging .dou-grid-layout__placeholder{transition:transform var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-grid-layout__resize{position:absolute;z-index:1;touch-action:none}.dou-grid-layout__resize.is-e{cursor:ew-resize;width:8px;top:8px;bottom:16px;right:-4px}.dou-grid-layout__resize.is-s{cursor:ns-resize;height:8px;bottom:-4px;left:8px;right:16px}.dou-grid-layout__resize.is-se{cursor:nwse-resize;opacity:0;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing);width:20px;height:20px;bottom:0;right:0}.dou-grid-layout__resize.is-se:after{position:absolute;box-sizing:border-box;border-right:2px solid var(--dou-color-text-tertiary);border-bottom:2px solid var(--dou-color-text-tertiary);content:"";border-bottom-right-radius:4px;width:8px;height:8px;bottom:5px;right:5px}.dou-grid-layout__item:hover>.dou-grid-layout__resize.is-se,.dou-grid-layout__item.is-resizing>.dou-grid-layout__resize.is-se{opacity:1}.dou-grid-layout__item:focus-visible>.dou-grid-layout__resize.is-se{opacity:1}@media (pointer:coarse){.dou-grid-layout__resize.is-se{opacity:1;width:32px;height:32px}}.dou-grid-layout__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}}@layer dou.components{.dou-dashboard{position:relative;outline:none;min-width:0}.dou-dashboard__widget{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:inherit;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);overflow:hidden;flex-direction:column;min-width:0;min-height:0}.dou-grid-layout__item.is-dragging>.dou-dashboard__widget,.dou-grid-layout__item.is-resizing>.dou-dashboard__widget{border-color:var(--dou-color-border-strong)}.dou-dashboard__widget.has-peers{outline:1.5px solid var(--dou-dashboard-peer-color);outline-offset:2px}.dou-dashboard__peers{position:absolute;z-index:1;display:flex;overflow:hidden;pointer-events:none;gap:4px;max-width:calc(100% - 24px);margin-bottom:-10px;bottom:100%;left:12px}.dou-dashboard__peer{background-color:var(--dou-dashboard-peer-color);color:oklch(from var(--dou-dashboard-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;flex:none;padding:0 6px;line-height:18px}.dou-dashboard__peer.is-focus{animation:dou-dashboard-peer-name var(--dou-motion-duration-fast)var(--dou-motion-easing)3s forwards}.dou-dashboard__header{display:flex;flex:none;align-items: center;gap:8px;height:40px;padding:0 8px 0 16px}.dou-dashboard__title{overflow:hidden;color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:min(6em,40%)}.dou-dashboard__title .dou-editable__view{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:inherit}.dou-dashboard__links{display:flex;overflow:hidden;flex:0 auto;gap:4px;min-width:0;max-width:60%}.dou-dashboard__links .dou-tag{min-width:0;max-width:100%}.dou-dashboard__links .dou-tag__label{overflow-x:clip;white-space:nowrap;text-overflow:ellipsis;min-width:0}.dou-dashboard__actions{display:flex;color:var(--dou-color-text-tertiary);flex:none;align-items: center;gap:2px}.dou-dashboard__export-error{flex:none;padding:0 8px 8px}.dou-dashboard__export-error .dou-alert__description{overflow-y:auto;max-height:4.5lh}.dou-dashboard__body{position:relative;flex:auto;min-width:0;min-height:0;padding:0 16px 16px}.dou-dashboard__body.is-fullscreen{height:100%;padding:0}.dou-dashboard__content{min-width:0;height:100%}.dou-dashboard__notice{display:grid;color:var(--dou-color-text-tertiary);text-align:center;place-items: center;height:100%}.dou-dashboard__status{position:absolute;display:flex;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:8px;padding:0 16px 16px;inset:0}.dou-dashboard__status.is-loading{background-color:color-mix(in oklab,var(--dou-color-bg-surface)72%,transparent);animation:dou-dashboard-fade-in var(--dou-motion-duration-fast)var(--dou-motion-easing).12s both}.dou-dashboard__status-icon{color:var(--dou-color-danger);width:20px;height:20px}.dou-dashboard__empty{position:absolute;display:grid;border:1px dashed var(--dou-color-border);border-radius:var(--dou-radius-container);pointer-events:none;place-items: center;inset:0}.dou-dashboard__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-dashboard__settings{display:flex;flex-direction:column;gap:16px}.dou-dashboard__field{display:flex;flex-direction:column;gap:8px}.dou-dashboard__field-hint{color:var(--dou-color-text-tertiary);font-size:var(--dou-font-size-sm)}.dou-dashboard__field-row{display:flex;flex-wrap:wrap;gap:16px}.dou-dashboard__field-row>.dou-dashboard__field{flex:120px;min-width:0}.dou-dashboard__columns{display:flex;flex-direction:column;gap:8px}.dou-dashboard__column{display:grid;grid-template-columns:minmax(0,1fr)minmax(0,1fr);align-items: center;gap:8px}.dou-dashboard__field-label{color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium)}@keyframes dou-dashboard-fade-in{0%{opacity:0}}.dou-dashboard-palette{display:flex;list-style:none;flex-direction:column;gap:8px;margin:0;padding:0}.dou-dashboard-palette.is-horizontal{flex-flow:wrap}.dou-dashboard-palette>li{margin:0}.dou-dashboard-palette__item{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:var(--dou-font-size-sm);cursor:grab;user-select:none;-webkit-touch-callout:none;transition:border-color var(--dou-motion-duration-fast)var(--dou-motion-easing);align-items: center;gap:8px;width:100%;height:32px;padding:0 12px}.dou-dashboard-palette__item:hover:not(:disabled){border-color:var(--dou-color-border-strong)}.dou-dashboard-palette__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-dashboard-palette__item:disabled{color:var(--dou-color-text-tertiary);cursor:not-allowed}.dou-dashboard-palette__icon{color:var(--dou-color-text-secondary);flex:none;width:16px;height:16px}.dou-dashboard-palette__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dou-dashboard-filter{display:flex;flex-wrap:wrap;align-items: center;gap:8px 16px}.dou-dashboard-filter__field{display:flex;align-items: center;gap:8px;min-width:0}.dou-dashboard-filter__label{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;flex:none}.dou-dashboard-filter__control{width:144px;min-width:0}.dou-dashboard-filter__control.is-range{width:272px}.dou-dashboard-filter__extra{display:flex;align-items: center;gap:4px;margin-left:auto}@media (max-width:480px){.dou-dashboard-filter__field{flex:100%}.dou-dashboard-filter__label{width:4em}.dou-dashboard-filter__control,.dou-dashboard-filter__control.is-range{flex:auto;width:auto}}.dou-dashboard-stat{display:flex;container-type:inline-size;flex-direction:column;justify-content:space-between;gap:8px;height:100%}@container (width<=200px){.dou-dashboard-stat .dou-statistic{--dou-statistic-value-size:22px}}.dou-dashboard-stat__spark{flex:none;margin:0 -16px -16px}.dou-dashboard-text{overflow:auto;color:var(--dou-color-text);white-space:pre-wrap;overflow-wrap:anywhere;height:100%;line-height:1.6}.dou-dashboard-text.is-sm{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-dashboard-text.is-md{font-size:var(--dou-font-size-md)}.dou-dashboard-text.is-lg{font-size:var(--dou-font-size-lg);font-weight:var(--dou-font-weight-medium);line-height:1.4}.dou-dashboard.is-exporting .dou-dashboard__actions{display:none}.dou-dashboard.is-exporting .dou-dashboard__links .dou-tag__close{display:none}.dou-dashboard.is-exporting .dou-dashboard__export-error{display:none}.dou-dashboard.is-exporting .dou-dashboard__peers{display:none}.dou-dashboard.is-exporting .dou-grid-layout__resize{display:none}.dou-dashboard.is-exporting .dou-dashboard__live{display:none}.dou-dashboard.is-exporting .dou-grid-layout__item{outline:none}.dou-dashboard.is-exporting .dou-dashboard__widget{outline:none}@media print{.dou-dashboard{print-color-adjust:exact}.dou-dashboard__actions,.dou-dashboard__links .dou-tag__close,.dou-dashboard__export-error,.dou-dashboard__peers,.dou-grid-layout__resize,.dou-dashboard-filter__clear,.dou-dashboard-filter__extra{display:none}.dou-grid-layout__item{outline:none;break-inside:avoid}.dou-dashboard__widget{outline:none}}}@keyframes dou-dashboard-peer-name{to{opacity:0;visibility:hidden}}
1
+ @layer dou.components{.dou-grid-layout{--dou-grid-item-radius:var(--dou-radius-container);--dou-grid-col:calc((100cqw - (var(--dou-grid-columns) - 1)*var(--dou-grid-gap-x))/var(--dou-grid-columns));position:relative;box-sizing:border-box;height:calc(var(--dou-grid-rows)*var(--dou-grid-row) + max(var(--dou-grid-rows) - 1,0)*var(--dou-grid-gap-y));container-type:inline-size;width:100%;min-width:0}.dou-grid-layout.is-pointer-dragging{cursor:grabbing}.dou-grid-layout.is-resizing{cursor:nwse-resize}.dou-grid-layout__item,.dou-grid-layout__placeholder{position:absolute;box-sizing:border-box;width:calc(var(--dou-grid-w)*var(--dou-grid-col) + (var(--dou-grid-w) - 1)*var(--dou-grid-gap-x) + var(--dou-grid-dw,0px));height:calc(var(--dou-grid-h)*var(--dou-grid-row) + (var(--dou-grid-h) - 1)*var(--dou-grid-gap-y) + var(--dou-grid-dh,0px));border-radius:var(--dou-grid-item-radius);transform:translate(calc(var(--dou-grid-x)*(var(--dou-grid-col) + var(--dou-grid-gap-x)) + var(--dou-grid-dx,0px)),calc(var(--dou-grid-y)*(var(--dou-grid-row) + var(--dou-grid-gap-y)) + var(--dou-grid-dy,0px)));top:0;left:0}.dou-grid-layout__item{display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);outline:none;min-width:0}.dou-grid-layout__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-grid-layout.is-editable .dou-grid-layout__item.is-movable{user-select:none;-webkit-touch-callout:none}.dou-grid-layout.is-editable:not(:-webkit-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:-moz-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:is(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-arranging .dou-grid-layout__item{transition:transform var(--dou-motion-duration-normal)var(--dou-motion-easing)}.dou-grid-layout__item.is-dragging,.dou-grid-layout__item.is-resizing{z-index:2;box-shadow:var(--dou-shadow-lg)}.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-dragging,.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-resizing{transition:none}.dou-grid-layout__placeholder{z-index:1;border:1px dashed var(--dou-color-border-strong);background-color:color-mix(in oklab,var(--dou-color-text)4%,transparent);pointer-events:none}.dou-grid-layout.is-arranging .dou-grid-layout__placeholder{transition:transform var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-grid-layout__resize{position:absolute;z-index:1;touch-action:none}.dou-grid-layout__resize.is-e{cursor:ew-resize;width:8px;top:8px;bottom:16px;right:-4px}.dou-grid-layout__resize.is-s{cursor:ns-resize;height:8px;bottom:-4px;left:8px;right:16px}.dou-grid-layout__resize.is-se{cursor:nwse-resize;opacity:0;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing);width:20px;height:20px;bottom:0;right:0}.dou-grid-layout__resize.is-se:after{position:absolute;box-sizing:border-box;border-right:2px solid var(--dou-color-text-tertiary);border-bottom:2px solid var(--dou-color-text-tertiary);content:"";border-bottom-right-radius:4px;width:8px;height:8px;bottom:5px;right:5px}.dou-grid-layout__item:hover>.dou-grid-layout__resize.is-se,.dou-grid-layout__item.is-resizing>.dou-grid-layout__resize.is-se{opacity:1}.dou-grid-layout__item:focus-visible>.dou-grid-layout__resize.is-se{opacity:1}@media (pointer:coarse){.dou-grid-layout__resize.is-se{opacity:1;width:32px;height:32px}}.dou-grid-layout__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}}@layer dou.components{.dou-dashboard{position:relative;outline:none;min-width:0}.dou-dashboard__widget{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:inherit;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);overflow:hidden;flex-direction:column;min-width:0;min-height:0}.dou-grid-layout__item.is-dragging>.dou-dashboard__widget,.dou-grid-layout__item.is-resizing>.dou-dashboard__widget{border-color:var(--dou-color-border-strong)}.dou-dashboard__widget.has-peers{outline:1.5px solid var(--dou-dashboard-peer-color);outline-offset:2px}.dou-dashboard__peers{position:absolute;z-index:1;display:flex;overflow:hidden;pointer-events:none;gap:4px;max-width:calc(100% - 24px);margin-bottom:-10px;bottom:100%;left:12px}.dou-dashboard__peer{background-color:var(--dou-dashboard-peer-color);color:oklch(from var(--dou-dashboard-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;flex:none;padding:0 6px;line-height:18px}.dou-dashboard__peer.is-focus{animation:dou-dashboard-peer-name var(--dou-motion-duration-fast)var(--dou-motion-easing)3s forwards}.dou-dashboard__header{display:flex;flex:none;align-items: center;gap:8px;height:40px;padding:0 8px 0 16px}.dou-dashboard__title{overflow:hidden;color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:min(6em,40%)}.dou-dashboard__title .dou-editable__view{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:inherit}.dou-dashboard__links{display:flex;overflow:hidden;flex:0 auto;gap:4px;min-width:0;max-width:60%}.dou-dashboard__links .dou-tag{min-width:0;max-width:100%}.dou-dashboard__links .dou-tag__label{overflow-x:clip;white-space:nowrap;text-overflow:ellipsis;min-width:0}.dou-dashboard__actions{display:flex;color:var(--dou-color-text-tertiary);flex:none;align-items: center;gap:2px}.dou-dashboard__comment{font-variant-numeric:tabular-nums}.dou-dashboard__comment:not(.has-threads){color:var(--dou-color-text-secondary)}@media (pointer:coarse){.dou-dashboard__comment.has-threads:after{position:absolute;content:"";inset:min(0px,50% - 20px)}}.dou-dashboard__fullscreen{display:flex;flex-direction:column;height:100%;min-height:0}.dou-dashboard__fullscreen>.dou-dashboard__body.is-fullscreen{flex:1;min-height:0}.dou-dashboard__fullscreen-bar{display:flex;justify-content:flex-end;margin-bottom:8px}.dou-dashboard__comment-card{box-sizing:border-box;max-height:min(var(--dou-floating-available,100vh),480px,calc(100vh - 32px));overflow-y:auto;overscroll-behavior:contain;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-container);background-color:color-mix(in oklab,var(--dou-color-text)calc(4%*var(--dou-scheme-dark)),var(--dou-color-bg-surface));box-shadow:var(--dou-shadow-md);width:min(340px,100vw - 32px);padding:12px}.dou-dashboard__comment-card>.dou-comment-thread+.dou-comment-thread{border-top:1px solid var(--dou-color-border-subtle);margin-top:12px;padding-top:12px}.dou-dashboard__export-error{flex:none;padding:0 8px 8px}.dou-dashboard__export-error .dou-alert__description{overflow-y:auto;max-height:4.5lh}.dou-dashboard__body{position:relative;flex:auto;min-width:0;min-height:0;padding:0 16px 16px}.dou-dashboard__body.is-fullscreen{height:100%;padding:0}.dou-dashboard__content{min-width:0;height:100%}.dou-dashboard__notice{display:grid;color:var(--dou-color-text-tertiary);text-align:center;place-items: center;height:100%}.dou-dashboard__status{position:absolute;display:flex;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:8px;padding:0 16px 16px;inset:0}.dou-dashboard__status.is-loading{background-color:color-mix(in oklab,var(--dou-color-bg-surface)72%,transparent);animation:dou-dashboard-fade-in var(--dou-motion-duration-fast)var(--dou-motion-easing).12s both}.dou-dashboard__settings-error{display:flex;color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;align-items: center;gap:8px;padding:24px 0}.dou-dashboard__status-icon{color:var(--dou-color-danger);width:20px;height:20px}.dou-dashboard__empty{position:absolute;display:grid;border:1px dashed var(--dou-color-border);border-radius:var(--dou-radius-container);pointer-events:none;place-items: center;inset:0}.dou-dashboard__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-dashboard__settings{display:flex;flex-direction:column;gap:16px}.dou-dashboard__field{display:flex;flex-direction:column;gap:8px}.dou-dashboard__field-hint{color:var(--dou-color-text-tertiary);font-size:var(--dou-font-size-sm)}.dou-dashboard__field-row{display:flex;flex-wrap:wrap;gap:16px}.dou-dashboard__field-row>.dou-dashboard__field{flex:120px;min-width:0}.dou-dashboard__columns{display:flex;flex-direction:column;gap:8px}.dou-dashboard__column{display:grid;grid-template-columns:minmax(0,1fr)minmax(0,1fr);align-items: center;gap:8px}.dou-dashboard__field-label{color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium)}@keyframes dou-dashboard-fade-in{0%{opacity:0}}.dou-dashboard-palette{display:flex;list-style:none;flex-direction:column;gap:8px;margin:0;padding:0}.dou-dashboard-palette.is-horizontal{flex-flow:wrap}.dou-dashboard-palette>li{margin:0}.dou-dashboard-palette__item{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:var(--dou-font-size-sm);cursor:grab;user-select:none;-webkit-touch-callout:none;transition:border-color var(--dou-motion-duration-fast)var(--dou-motion-easing);align-items: center;gap:8px;width:100%;height:32px;padding:0 12px}.dou-dashboard-palette__item:hover:not(:disabled){border-color:var(--dou-color-border-strong)}.dou-dashboard-palette__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-dashboard-palette__item:disabled{color:var(--dou-color-text-tertiary);cursor:not-allowed}.dou-dashboard-palette__icon{color:var(--dou-color-text-secondary);flex:none;width:16px;height:16px}.dou-dashboard-palette__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dou-dashboard-filter{display:flex;flex-wrap:wrap;align-items: center;gap:8px 16px}.dou-dashboard-filter__field{display:flex;align-items: center;gap:8px;min-width:0}.dou-dashboard-filter__label{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;flex:none}.dou-dashboard-filter__control{width:144px;min-width:0}.dou-dashboard-filter__control.is-range{width:272px}.dou-dashboard-filter__extra{display:flex;align-items: center;gap:4px;margin-left:auto}@media (max-width:480px){.dou-dashboard-filter__field{flex:100%}.dou-dashboard-filter__label{width:4em}.dou-dashboard-filter__control,.dou-dashboard-filter__control.is-range{flex:auto;width:auto}}.dou-dashboard-stat{display:flex;container-type:inline-size;flex-direction:column;justify-content:space-between;gap:8px;height:100%}@container (width<=200px){.dou-dashboard-stat .dou-statistic{--dou-statistic-value-size:22px}}.dou-dashboard-stat__spark{flex:none;margin:0 -16px -16px}.dou-dashboard-text{overflow:auto;color:var(--dou-color-text);white-space:pre-wrap;overflow-wrap:anywhere;height:100%;line-height:1.6}.dou-dashboard-text.is-sm{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-dashboard-text.is-md{font-size:var(--dou-font-size-md)}.dou-dashboard-text.is-lg{font-size:var(--dou-font-size-lg);font-weight:var(--dou-font-weight-medium);line-height:1.4}.dou-dashboard.is-exporting .dou-dashboard__actions{display:none}.dou-dashboard.is-exporting .dou-dashboard__links .dou-tag__close{display:none}.dou-dashboard.is-exporting .dou-dashboard__export-error{display:none}.dou-dashboard.is-exporting .dou-dashboard__peers{display:none}.dou-dashboard.is-exporting .dou-grid-layout__resize{display:none}.dou-dashboard.is-exporting .dou-dashboard__live{display:none}.dou-dashboard.is-exporting .dou-grid-layout__item{outline:none}.dou-dashboard.is-exporting .dou-dashboard__widget{outline:none}@media print{.dou-dashboard{print-color-adjust:exact}.dou-dashboard__actions,.dou-dashboard__links .dou-tag__close,.dou-dashboard__export-error,.dou-dashboard__peers,.dou-grid-layout__resize,.dou-dashboard-filter__clear,.dou-dashboard-filter__extra{display:none}.dou-grid-layout__item{outline:none;break-inside:avoid}.dou-dashboard__widget{outline:none}}}@keyframes dou-dashboard-peer-name{to{opacity:0;visibility:hidden}}
package/dist/style.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import 'dou-ui/components/alert/style'
2
+ import 'dou-ui/components/autocomplete/style'
3
+ import 'dou-ui/components/comment-thread/style'
2
4
  import 'dou-ui/components/date-picker/style'
3
5
  import 'dou-ui/components/dialog/style'
4
6
  import 'dou-ui/components/drawer/style'
5
7
  import 'dou-ui/components/editable/style'
6
- import 'dou-ui/components/dropdown/style'
7
8
  import 'dou-ui/components/grid/style'
8
9
  import 'dou-ui/components/input-number/style'
9
10
  import 'dou-ui/components/segmented-control/style'
@@ -12,7 +13,5 @@ import 'dou-ui/components/sparkline/style'
12
13
  import 'dou-ui/components/statistic/style'
13
14
  import 'dou-ui/components/switch/style'
14
15
  import 'dou-ui/components/table/style'
15
- import 'dou-ui/components/textarea/style'
16
- import 'dou-ui/components/tooltip/style'
17
16
  import '@dou-ui/sheet/style'
18
17
  import './style.css'
@@ -0,0 +1,3 @@
1
+ import type { ChartWidgetProps } from './types';
2
+ /** The chart widget's props as its type says; what isn't the right type counts as not set. */
3
+ export declare function chartPropsOf(props: Record<string, unknown>): ChartWidgetProps;
@@ -3,7 +3,7 @@ import type { DashboardDocument, DashboardPlace } from './types';
3
3
  /** A dashboard with no widgets, the `v-model` when none is bound. */
4
4
  export declare const emptyDocument: () => DashboardDocument;
5
5
  export interface DocumentProblem {
6
- code: 'version' | 'shape' | 'duplicate-id' | 'missing-id' | 'unknown-type' | 'bad-place';
6
+ code: 'version' | 'shape' | 'duplicate-id' | 'missing-id' | 'unknown-type' | 'bad-place' | 'bad-comments';
7
7
  /** The widget at fault; none for the document's own problems. */
8
8
  widgetId?: string;
9
9
  /** Where the problem is, e.g. `widgets[2]` or `widgets[2].place.lg`; `version` for the version. */
@@ -22,7 +22,8 @@ export declare function isDashboardPlace(value: unknown): value is DashboardPlac
22
22
  /**
23
23
  * The problems of a dashboard document, before it is saved or shown: an
24
24
  * unknown version, widgets without an id or sharing one, types nobody
25
- * registered, and places that are not whole cells.
25
+ * registered, places that are not whole cells, and `comments` that are
26
+ * not a list of thread ids.
26
27
  */
27
28
  export declare function checkDocument(document: DashboardDocument, options?: CheckDocumentOptions): DocumentProblem[];
28
29
  /**
@@ -1,5 +1,5 @@
1
1
  import type { DashboardTransaction } from './transaction';
2
- import type { DashboardDocument } from './types';
2
+ import type { DashboardDocument, DashboardWidget } from './types';
3
3
  /** Undo and redo of a dashboard: the steps of each transaction and the steps that undo them. */
4
4
  export declare class DashboardHistory {
5
5
  private depth;
@@ -11,5 +11,11 @@ export declare class DashboardHistory {
11
11
  record(tr: DashboardTransaction, now?: number): void;
12
12
  undo(document: DashboardDocument): DashboardTransaction | null;
13
13
  redo(document: DashboardDocument): DashboardTransaction | null;
14
+ /**
15
+ * Gives a change kept out of undo to the widget as undo and redo bring it
16
+ * back, too: comments started on a widget stay on it when its adding is
17
+ * undone and redone.
18
+ */
19
+ carry(id: string, patch: Partial<DashboardWidget>): void;
14
20
  clear(): void;
15
21
  }
@@ -31,6 +31,10 @@ export interface DashboardTransactionMeta {
31
31
  origin?: string;
32
32
  [key: string]: unknown;
33
33
  }
34
+ export interface ReplaceWidgetsOptions {
35
+ /** A widget that stays keeps its `comments`; `true` by default. */
36
+ keepComments?: boolean;
37
+ }
34
38
  /** Deep equality of JSON values; key order doesn't matter. */
35
39
  export declare function sameValue(a: unknown, b: unknown): boolean;
36
40
  /**
@@ -82,5 +86,10 @@ export declare const cloneJson: <T>(value: T) => T;
82
86
  * that are gone are removed, new ones added, changed keys updated, and the
83
87
  * fewest widgets taken out and put back to match the order. Unchanged
84
88
  * widgets keep their objects.
89
+ *
90
+ * A widget that stays keeps its `comments`, the discussions on it, as they
91
+ * are: restoring a default layout doesn't take them off. Pass
92
+ * `{ keepComments: false }` for the exact steps, e.g. to apply a shared
93
+ * document.
85
94
  */
86
- export declare function replaceWidgets(tr: DashboardTransaction, next: DashboardDocument): DashboardTransaction;
95
+ export declare function replaceWidgets(tr: DashboardTransaction, next: DashboardDocument, options?: ReplaceWidgetsOptions): DashboardTransaction;
@@ -19,6 +19,11 @@ export interface DashboardWidget<P extends object = Record<string, unknown>> {
19
19
  * main one; a narrower breakpoint without one is laid out from it.
20
20
  */
21
21
  place: Partial<Record<string, DashboardPlace>>;
22
+ /**
23
+ * The ids of the comment threads about this widget, see the dashboard's
24
+ * `comments`. Kept when the widget is removed and brought back by undo.
25
+ */
26
+ comments?: string[];
22
27
  }
23
28
  /** A dashboard: a JSON document the app saves and loads itself. */
24
29
  export interface DashboardDocument {
@@ -0,0 +1,15 @@
1
+ import { type Placement } from 'dou-ui';
2
+ import { type DashboardMessages } from '../locale';
3
+ import type { DashboardComments } from './comments';
4
+ type __VLS_Props = {
5
+ id: string;
6
+ comments: DashboardComments;
7
+ messages: DashboardMessages;
8
+ /** Where the tooltip goes: in the full screen view, clear of the dialog's close button above. */
9
+ tooltipPlacement?: Placement;
10
+ };
11
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
12
+ tooltipPlacement: Placement;
13
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const _default: typeof __VLS_export;
15
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import type { DashboardMessages } from '../locale';
2
+ import type { DashboardComments } from './comments';
3
+ type __VLS_Props = {
4
+ comments: DashboardComments;
5
+ messages: DashboardMessages;
6
+ /** The comment button of a widget, to put the card by and give the focus back to. */
7
+ buttonOf: (widget: string) => HTMLElement | null;
8
+ /** Where the card goes: the button, or the widget while its button isn't drawn yet. */
9
+ placeOf: (widget: string) => HTMLElement | null;
10
+ };
11
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
@@ -0,0 +1,44 @@
1
+ import { type CommentAction, type CommentThread } from 'dou-ui';
2
+ import { type ComputedRef, type Ref } from 'vue';
3
+ import type { DashboardStep, DashboardTransactionMeta } from '../core/transaction';
4
+ import type { DashboardDocument } from '../core/types';
5
+ import type { DashboardCommentAnchor, DashboardEmits, DashboardProps } from './types';
6
+ type Emit = <K extends keyof DashboardEmits>(event: K, ...args: DashboardEmits[K]) => void;
7
+ /** The thread ids on a widget; nothing when a hand-written document has something else there. */
8
+ export declare const commentIdsOf: (widget: {
9
+ comments?: unknown;
10
+ }) => string[];
11
+ /**
12
+ * The comments of a dashboard: which widget each thread is about, the thread
13
+ * open now, and the one being started.
14
+ */
15
+ export declare function useDashboardComments(options: {
16
+ props: Omit<DashboardProps, 'modelValue' | 'filters'>;
17
+ emit: Emit;
18
+ model: Ref<DashboardDocument>;
19
+ run: (steps: DashboardStep[], meta: DashboardTransactionMeta) => unknown;
20
+ /** Keeps a change out of undo on the widget as undo and redo bring it back. */
21
+ carry: (id: string, patch: {
22
+ comments: string[] | undefined;
23
+ }) => void;
24
+ }): {
25
+ enabled: ComputedRef<boolean>;
26
+ writable: ComputedRef<boolean>;
27
+ threads: ComputedRef<readonly CommentThread[]>;
28
+ author: ComputedRef<import("dou-ui").CommentAuthor | undefined>;
29
+ active: ComputedRef<string | null>;
30
+ pending: import("vue").ShallowRef<string | null, string | null>;
31
+ focusRequest: import("vue").ShallowRef<number, number>;
32
+ openOn: ComputedRef<Map<string, string[]>>;
33
+ current: ComputedRef<string | null>;
34
+ shown: ComputedRef<CommentThread[]>;
35
+ start: (widget: string, focus?: boolean) => boolean;
36
+ apply: (action: CommentAction) => void;
37
+ open: (id: string | null) => void;
38
+ close: () => void;
39
+ openedHere: (id: string | null) => boolean;
40
+ anchors: () => Record<string, DashboardCommentAnchor | null>;
41
+ widgetOf: (id: string) => string | null;
42
+ };
43
+ export type DashboardComments = ReturnType<typeof useDashboardComments>;
44
+ export {};