@digitalwalletcorp/vue-core 1.4.0 → 1.4.2

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 (110) hide show
  1. package/lib/accordion-section.d.cts +1 -1
  2. package/lib/accordion-section.d.ts +1 -1
  3. package/lib/{components-B2jz-g6A.js → components-Mk1fpjbw.js} +5 -5
  4. package/lib/components-ytOBcKlQ.cjs +1 -0
  5. package/lib/data-table.d.cts +1 -1
  6. package/lib/data-table.d.ts +1 -1
  7. package/lib/{types → helpers}/data-table.d.cts +47 -0
  8. package/lib/{types → helpers}/data-table.d.ts +47 -0
  9. package/lib/helpers/{show-floating-component.d.cts → floating-component.d.cts} +1 -1
  10. package/lib/helpers/{show-floating-component.d.ts → floating-component.d.ts} +1 -1
  11. package/lib/helpers/{show-modal-dialog.d.cts → modal-dialog.d.cts} +21 -7
  12. package/lib/helpers/{show-modal-dialog.d.ts → modal-dialog.d.ts} +21 -7
  13. package/lib/helpers/{show-overlay-box.d.ts → overlay-box.d.cts} +3 -1
  14. package/lib/helpers/{show-overlay-box.d.cts → overlay-box.d.ts} +3 -1
  15. package/lib/helpers/{show-snackbar.d.cts → snackbar.d.cts} +16 -1
  16. package/lib/helpers/{show-snackbar.d.ts → snackbar.d.ts} +16 -1
  17. package/lib/index.cjs +1 -1
  18. package/lib/index.d.cts +15 -18
  19. package/lib/index.d.ts +15 -18
  20. package/lib/index.js +181 -265
  21. package/lib/internal/data-table-controls.d.cts +1 -1
  22. package/lib/internal/data-table-controls.d.ts +1 -1
  23. package/lib/internal/floating-component.d.cts +1 -1
  24. package/lib/internal/floating-component.d.ts +1 -1
  25. package/lib/internal/message.d.cts +11 -0
  26. package/lib/internal/message.d.ts +11 -0
  27. package/lib/internal/movable-window.d.cts +1 -1
  28. package/lib/internal/movable-window.d.ts +1 -1
  29. package/lib/internal/pagination.d.cts +1 -1
  30. package/lib/internal/pagination.d.ts +1 -1
  31. package/lib/internal/snackbar-container.d.cts +1 -1
  32. package/lib/internal/snackbar-container.d.ts +1 -1
  33. package/lib/internal/use-movable-window.d.cts +1 -1
  34. package/lib/internal/use-movable-window.d.ts +1 -1
  35. package/lib/internal/{mount-window.d.cts → window-control.d.cts} +22 -1
  36. package/lib/internal/{mount-window.d.ts → window-control.d.ts} +22 -1
  37. package/lib/label-button.d.cts +1 -1
  38. package/lib/label-button.d.ts +1 -1
  39. package/lib/label-icon.d.cts +12 -2
  40. package/lib/label-icon.d.ts +12 -2
  41. package/lib/modal-dialog.d.cts +5 -5
  42. package/lib/modal-dialog.d.ts +5 -5
  43. package/lib/nuxt.cjs +1 -1
  44. package/lib/nuxt.js +1 -1
  45. package/lib/overlay-box.d.cts +1 -1
  46. package/lib/overlay-box.d.ts +1 -1
  47. package/lib/register.cjs +1 -1
  48. package/lib/register.js +1 -1
  49. package/lib/style.css +1 -1
  50. package/lib/tab-content.d.cts +1 -1
  51. package/lib/tab-content.d.ts +1 -1
  52. package/lib/warning-popper.vue_vue_type_style_index_0_lang-142lRixg.cjs +4 -0
  53. package/lib/warning-popper.vue_vue_type_style_index_0_lang-BKR56ef2.js +2019 -0
  54. package/package.json +1 -1
  55. package/src/accordion-section.vue +1 -1
  56. package/src/data-table.vue +2 -2
  57. package/src/helpers/data-table.ts +250 -0
  58. package/src/helpers/{show-floating-component.ts → floating-component.ts} +3 -6
  59. package/src/helpers/{show-modal-dialog.ts → modal-dialog.ts} +26 -7
  60. package/src/helpers/{show-overlay-box.ts → overlay-box.ts} +5 -2
  61. package/src/helpers/{show-snackbar.ts → snackbar.ts} +19 -1
  62. package/src/index.ts +15 -18
  63. package/src/internal/data-table-controls.vue +1 -1
  64. package/src/internal/floating-component.vue +2 -2
  65. package/src/internal/message.ts +118 -0
  66. package/src/internal/movable-window.vue +1 -1
  67. package/src/internal/pagination.vue +1 -1
  68. package/src/internal/snackbar-container.vue +1 -1
  69. package/src/internal/use-movable-window.ts +1 -1
  70. package/src/internal/{mount-window.ts → window-control.ts} +31 -1
  71. package/src/label-button.vue +1 -1
  72. package/src/label-icon.vue +13 -2
  73. package/src/modal-dialog.vue +17 -10
  74. package/src/overlay-box.vue +3 -3
  75. package/src/tab-content.vue +2 -2
  76. package/src/tab-group.vue +2 -2
  77. package/lib/components-COL2ZbhC.cjs +0 -1
  78. package/lib/helpers/data-table-csv.d.cts +0 -17
  79. package/lib/helpers/data-table-csv.d.ts +0 -17
  80. package/lib/internal/data-table-value.d.cts +0 -32
  81. package/lib/internal/data-table-value.d.ts +0 -32
  82. package/lib/internal/opened-overlay-boxes.d.cts +0 -2
  83. package/lib/internal/opened-overlay-boxes.d.ts +0 -2
  84. package/lib/internal/snackbar-item.d.cts +0 -17
  85. package/lib/internal/snackbar-item.d.ts +0 -17
  86. package/lib/internal/window-order.d.cts +0 -6
  87. package/lib/internal/window-order.d.ts +0 -6
  88. package/lib/types/label-preset.d.cts +0 -12
  89. package/lib/types/label-preset.d.ts +0 -12
  90. package/lib/types/modal-dialog.d.cts +0 -13
  91. package/lib/types/modal-dialog.d.ts +0 -13
  92. package/lib/types/movable-window.d.cts +0 -16
  93. package/lib/types/movable-window.d.ts +0 -16
  94. package/lib/warning-popper.vue_vue_type_style_index_0_lang-4FIOsOY5.cjs +0 -1
  95. package/lib/warning-popper.vue_vue_type_style_index_0_lang-CgXoSjjp.js +0 -1865
  96. package/src/helpers/data-table-csv.ts +0 -55
  97. package/src/internal/data-table-value.ts +0 -99
  98. package/src/internal/opened-overlay-boxes.ts +0 -2
  99. package/src/internal/snackbar-item.ts +0 -20
  100. package/src/internal/window-order.ts +0 -11
  101. package/src/types/data-table.ts +0 -99
  102. package/src/types/label-preset.ts +0 -13
  103. package/src/types/modal-dialog.ts +0 -16
  104. package/src/types/movable-window.ts +0 -18
  105. /package/lib/helpers/{show-screen-loading.d.cts → screen-loading.d.cts} +0 -0
  106. /package/lib/helpers/{show-screen-loading.d.ts → screen-loading.d.ts} +0 -0
  107. /package/lib/internal/{tab-group-context.d.cts → tab-group.d.cts} +0 -0
  108. /package/lib/internal/{tab-group-context.d.ts → tab-group.d.ts} +0 -0
  109. /package/src/helpers/{show-screen-loading.ts → screen-loading.ts} +0 -0
  110. /package/src/internal/{tab-group-context.ts → tab-group.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalwalletcorp/vue-core",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "description": "Basic UI components for Vue 3",
6
6
  "main": "lib/index.cjs",
@@ -56,7 +56,7 @@ import type { Component, Slot } from 'vue';
56
56
  import { SvgTriangleButton } from '@digitalwalletcorp/vue-svg-icons';
57
57
  import LabelIcon from '@/label-icon.vue';
58
58
  import { useShrinkable } from '@/internal/use-shrinkable';
59
- import type { LabelPreset } from '@/types/label-preset';
59
+ import type { LabelPreset } from '@/label-icon.vue';
60
60
 
61
61
  // 開閉ボタンのアイコンとラベルは別々に決める。どちらも、スロット/ラベルの指定 > プリセット の順で使う
62
62
  // 何も指定が無い場合だけ、既定の三角を表示する
@@ -132,10 +132,10 @@ import { computed, inject, onBeforeUnmount, onMounted, ref, shallowRef, watch }
132
132
  import type { ClassValue, StyleValue } from 'vue';
133
133
  import { SvgPointingTriangle } from '@digitalwalletcorp/vue-svg-icons';
134
134
  import DataTableControls from '@/internal/data-table-controls.vue';
135
- import { compareValues, getValueByPath, resolveLabel, stringifyValue } from '@/internal/data-table-value';
135
+ import { compareValues, getValueByPath, resolveLabel, stringifyValue } from '@/helpers/data-table';
136
136
  import { vueCoreOptionsKey } from '@/helpers/vue-core-options';
137
137
  import type { DataTableOptions } from '@/helpers/vue-core-options';
138
- import type { DataTableControlsPlacement, DataTableHeader, DataTableLabels, DataTableResolvedLabels, DataTableSortContext, DataTableSortMode } from '@/types/data-table';
138
+ import type { DataTableControlsPlacement, DataTableHeader, DataTableLabels, DataTableResolvedLabels, DataTableSortContext, DataTableSortMode } from '@/helpers/data-table';
139
139
 
140
140
  /**
141
141
  * DataTable の props
@@ -0,0 +1,250 @@
1
+ /** 列の値の型。ソートの比較方法を決める */
2
+ export type DataTableValueType = 'boolean' | 'string' | 'number' | 'object';
3
+
4
+ /** ソートの方式。page は表示中の行を並べ替えて表示し、remote はソート条件を通知するだけで利用側が再取得する */
5
+ export type DataTableSortMode = 'page' | 'remote';
6
+
7
+ /** コントロール(ページネーション・総件数・表示件数・ダウンロードボタン)を出す位置 */
8
+ export type DataTableControlsPlacement = 'both' | 'top' | 'bottom' | 'none';
9
+
10
+ /**
11
+ * CSV に出力する列の定義
12
+ */
13
+ export interface DataTableCsvColumn<T = unknown> {
14
+ /** true なら出力しない */
15
+ disabled?: boolean;
16
+ /** 値を取り出すキー。ドット区切りで入れ子を辿る。未指定なら DataTableHeader.id。'$index' は行番号 */
17
+ key?: string;
18
+ /** 列名。未指定なら DataTableHeader.label。言語切替に追従させる場合は関数で渡す */
19
+ label?: string | (() => string);
20
+ /** 値の整形。指定したときは key を使わない */
21
+ format?: (row: T) => unknown;
22
+ }
23
+
24
+ /**
25
+ * ヘッダの定義
26
+ */
27
+ export interface DataTableHeader<T = unknown> {
28
+ /** 列を識別するキー。ソートで値を取り出すキーにもなる */
29
+ id: string;
30
+ /** 見出し。言語切替に追従させる場合は関数で渡す */
31
+ label: string | (() => string);
32
+ /** true なら label を HTML として描画する */
33
+ html?: boolean;
34
+ /** ソートで値を取り出すキー。id と違うキーで並べるときに指定する。ドット区切りで入れ子を辿る */
35
+ sortKey?: string;
36
+ /** 値の型。ソートの比較方法を決める。未指定なら string */
37
+ type?: DataTableValueType;
38
+ /** 行同士を比較する関数。指定したときは sortKey と type を使わない。昇順の並びで a が前なら負の数を返す */
39
+ compare?: (a: T, b: T) => number;
40
+ /** 列の幅。数値は px */
41
+ width?: string | number;
42
+ /** 列の最小幅。数値は px */
43
+ minWidth?: string | number;
44
+ /** 列の最大幅。数値は px */
45
+ maxWidth?: string | number;
46
+ /** th の rowspan */
47
+ rowspan?: string | number;
48
+ /** th の colspan */
49
+ colspan?: string | number;
50
+ /** th の title 属性 */
51
+ title?: string;
52
+ /** CSV の出力定義。true なら id の値を label の列名で出力する。未指定なら出力しない */
53
+ csv?: boolean | DataTableCsvColumn<T>[];
54
+ }
55
+
56
+ /**
57
+ * 表示する文言。言語切替に追従させる場合は関数で渡す
58
+ */
59
+ export interface DataTableLabels {
60
+ /** 総件数の見出し */
61
+ totalCount?: string | (() => string);
62
+ /** 総件数の後ろに付ける単位 */
63
+ totalUnit?: string | (() => string);
64
+ /** 1ページあたりの表示件数の見出し */
65
+ limit?: string | (() => string);
66
+ /** データが無いときの表示 */
67
+ noData?: string | (() => string);
68
+ /** ページ番号の選択の見出し。showPageSelect のときに表示する */
69
+ pageNumber?: string | (() => string);
70
+ /** ページダウンロードボタンの title */
71
+ downloadPage?: string | (() => string);
72
+ /** 全件ダウンロードボタンの title */
73
+ downloadAll?: string | (() => string);
74
+ /** 先頭ページへ移動するボタンの読み上げ名 */
75
+ firstPage?: string | (() => string);
76
+ /** 前のページへ移動するボタンの読み上げ名 */
77
+ previousPage?: string | (() => string);
78
+ /** 前のページ番号の組へ移動するボタンの読み上げ名 */
79
+ previousPages?: string | (() => string);
80
+ /** 次のページ番号の組へ移動するボタンの読み上げ名 */
81
+ nextPages?: string | (() => string);
82
+ /** 次のページへ移動するボタンの読み上げ名 */
83
+ nextPage?: string | (() => string);
84
+ /** 末尾ページへ移動するボタンの読み上げ名 */
85
+ lastPage?: string | (() => string);
86
+ }
87
+
88
+ /** 関数を評価した後の文言 */
89
+ export type DataTableResolvedLabels = Record<keyof DataTableLabels, string>;
90
+
91
+ /**
92
+ * ソートの状態
93
+ */
94
+ export interface DataTableSortContext {
95
+ /** ソートしているヘッダの id。ソートしていなければ空文字 */
96
+ sortKey: string;
97
+ /** 降順なら true */
98
+ descending: boolean;
99
+ }
100
+
101
+ /**
102
+ * ドット区切りのパスで入れ子の値を取り出す。途中が null なら undefined
103
+ *
104
+ * @param {unknown} obj
105
+ * @param {string} path 'a.b.c' の形。'a[0].b' は 'a.0.b' と同じ
106
+ * @returns {unknown}
107
+ */
108
+ export const getValueByPath = (obj: unknown, path: string): unknown => {
109
+ let value: unknown = obj;
110
+ for (const key of path.replace(/\[(\w+)\]/g, '.$1').split('.')) {
111
+ if (value == null) {
112
+ return undefined;
113
+ }
114
+ value = (value as Record<string, unknown>)[key];
115
+ }
116
+ return value;
117
+ };
118
+
119
+ /**
120
+ * 文字列または文字列を返す関数から文字列を得る
121
+ *
122
+ * @param {string | (() => string)} label
123
+ * @returns {string}
124
+ */
125
+ export const resolveLabel = (label: string | (() => string) | undefined): string => {
126
+ if (typeof label === 'function') {
127
+ return label();
128
+ }
129
+ return label ?? '';
130
+ };
131
+
132
+ const toBoolean = (value: unknown): boolean => {
133
+ return value === true || value === 'true' || value === '1' || value === 'on' || value === 1;
134
+ };
135
+
136
+ /**
137
+ * カンマ付きの文字列も数値として扱うため、符号・数字・小数点だけを残して数値化する
138
+ */
139
+ const toNumber = (value: unknown): number => {
140
+ if (typeof value === 'number') {
141
+ return value;
142
+ }
143
+ return Number(String(value).replace(/[^+\-\d.]/g, ''));
144
+ };
145
+
146
+ /**
147
+ * 型に応じて2つの値を比較する。null / undefined は最小として扱う
148
+ *
149
+ * @param {unknown} a
150
+ * @param {unknown} b
151
+ * @param {DataTableValueType} type
152
+ * @returns {number} a が前なら負の数、後ろなら正の数、等しければ 0
153
+ */
154
+ export const compareValues = (a: unknown, b: unknown, type: DataTableValueType): number => {
155
+ if (a == null && b == null) {
156
+ return 0;
157
+ }
158
+ if (a == null) {
159
+ return -1;
160
+ }
161
+ if (b == null) {
162
+ return 1;
163
+ }
164
+ if (a === b) {
165
+ return 0;
166
+ }
167
+ switch (type) {
168
+ case 'boolean':
169
+ return (toBoolean(a) ? 1 : 0) - (toBoolean(b) ? 1 : 0);
170
+ case 'number': {
171
+ const numA = toNumber(a);
172
+ const numB = toNumber(b);
173
+ if (Number.isNaN(numA) || Number.isNaN(numB)) {
174
+ return (Number.isNaN(numA) ? 0 : 1) - (Number.isNaN(numB) ? 0 : 1);
175
+ }
176
+ return numA - numB;
177
+ }
178
+ case 'object':
179
+ return stringifyValue(a).localeCompare(stringifyValue(b));
180
+ default:
181
+ return String(a).localeCompare(String(b));
182
+ }
183
+ };
184
+
185
+ /**
186
+ * 行の同一性の判定に使う文字列にする。bigint は文字列にし、循環参照は空文字にする
187
+ *
188
+ * @param {unknown} value
189
+ * @returns {string}
190
+ */
191
+ export const stringifyValue = (value: unknown): string => {
192
+ try {
193
+ return JSON.stringify(value, (_, v) => typeof v === 'bigint' ? v.toString() : v) ?? '';
194
+ } catch {
195
+ return '';
196
+ }
197
+ };
198
+
199
+ /** 行番号を出力するキー */
200
+ const INDEX_KEY = '$index';
201
+
202
+ /**
203
+ * ヘッダから CSV に出力する列の定義を取り出す。csv を持たないヘッダと disabled の列は含めない
204
+ */
205
+ const toCsvColumns = <T>(headers: DataTableHeader<T>[]): { header: DataTableHeader<T>; column: DataTableCsvColumn<T> }[] => {
206
+ const columns: { header: DataTableHeader<T>; column: DataTableCsvColumn<T> }[] = [];
207
+ for (const header of headers) {
208
+ if (header.csv === true) {
209
+ columns.push({ header, column: {} });
210
+ } else if (Array.isArray(header.csv)) {
211
+ for (const column of header.csv) {
212
+ if (!column.disabled) {
213
+ columns.push({ header, column });
214
+ }
215
+ }
216
+ }
217
+ }
218
+ return columns;
219
+ };
220
+
221
+ /**
222
+ * ヘッダの csv の定義から CSV の列名を作る
223
+ *
224
+ * @param {DataTableHeader<T>[]} headers
225
+ * @returns {string[]} 列名
226
+ */
227
+ export const headersToCsvColumns = <T>(headers: DataTableHeader<T>[]): string[] => {
228
+ return toCsvColumns(headers).map(({ header, column }) => resolveLabel(column.label ?? header.label));
229
+ };
230
+
231
+ /**
232
+ * ヘッダの csv の定義に従って行から CSV の列の値を取り出す
233
+ *
234
+ * @param {DataTableHeader<T>[]} headers
235
+ * @param {T} row
236
+ * @param {number} [rowNumber] key が '$index' の列に出力する行番号
237
+ * @returns {unknown[]} 列の値。文字列化はしない
238
+ */
239
+ export const rowToCsvColumns = <T>(headers: DataTableHeader<T>[], row: T, rowNumber?: number): unknown[] => {
240
+ return toCsvColumns(headers).map(({ header, column }) => {
241
+ if (column.format) {
242
+ return column.format(row);
243
+ }
244
+ const key = column.key ?? header.id;
245
+ if (key === INDEX_KEY) {
246
+ return rowNumber;
247
+ }
248
+ return getValueByPath(row, key);
249
+ });
250
+ };
@@ -1,8 +1,9 @@
1
1
  import { h } from 'vue';
2
2
  import type { AppContext, ClassValue, Component, StyleValue, VNode } from 'vue';
3
3
  import FloatingComponent from '@/internal/floating-component.vue';
4
- import { mountWindow, useWindowOwner } from '@/internal/mount-window';
5
- import type { MovableWindowContentProps, MovableWindowDragMode, MovableWindowHandle } from '@/types/movable-window';
4
+ import { toMessageText } from '@/internal/message';
5
+ import { mountWindow, useWindowOwner } from '@/internal/window-control';
6
+ import type { MovableWindowContentProps, MovableWindowDragMode, MovableWindowHandle } from '@/internal/window-control';
6
7
 
7
8
  /** showFloatingComponent が中身のコンポーネントに props として渡す関数 */
8
9
  export type FloatingComponentContentProps = MovableWindowContentProps;
@@ -89,10 +90,6 @@ const renderComponent = (component: Component, props?: Record<string, unknown>)
89
90
  });
90
91
  };
91
92
 
92
- const toMessageText = (message: string | object): string => {
93
- return typeof message === 'string' ? message : JSON.stringify(message, null, 2);
94
- };
95
-
96
93
  const renderMessage = (message: string | object, html: boolean | undefined) => (): VNode => {
97
94
  if (html && typeof message === 'string') {
98
95
  return h('div', { class: 'dwui-floating-component-message', innerHTML: message });
@@ -1,7 +1,26 @@
1
1
  import { h, render } from 'vue';
2
2
  import type { AppContext, ClassValue, Component, StyleValue } from 'vue';
3
3
  import ModalDialog from '@/modal-dialog.vue';
4
- import type { ModalDialogButton, ModalDialogImage, ModalDialogResult, ModalDialogType } from '@/types/modal-dialog';
4
+
5
+ /** モーダルダイアログに表示するメッセージ。オブジェクトは整形した JSON 風のテキストで表示する */
6
+ export type ModalDialogMessage = string | object;
7
+
8
+ /** モーダルダイアログの種類 */
9
+ export type ModalDialogType = 'info' | 'confirm' | 'warn' | 'error';
10
+
11
+ /** モーダルダイアログに並べるボタンの種類 */
12
+ export type ModalDialogButton = 'ok' | 'yes' | 'no' | 'cancel';
13
+
14
+ /** モーダルダイアログを閉じたボタン。Esc で閉じたときは cancel */
15
+ export type ModalDialogResult = ModalDialogButton;
16
+
17
+ /** モーダルダイアログに表示する画像。文字列は画像の URL */
18
+ export type ModalDialogImage = string | {
19
+ /** 画像の URL */
20
+ src: string;
21
+ /** 代替テキスト */
22
+ alt: string;
23
+ };
5
24
 
6
25
  export interface ShowModalDialogOptions {
7
26
  /** ダイアログの種類 */
@@ -38,11 +57,11 @@ export interface ShowModalDialogOptions {
38
57
  /**
39
58
  * ModalDialog を body の末尾に描画して開き、閉じたら取り外す。ブラウザでのみ動作する
40
59
  *
41
- * @param {string | string[]} message 表示する文字列。配列なら1要素を1段落として表示する
60
+ * @param {ModalDialogMessage | ModalDialogMessage[]} message 表示するメッセージ。配列なら1要素を1段落として表示する
42
61
  * @param {ShowModalDialogOptions} [options]
43
62
  * @returns {Promise<ModalDialogResult>} 閉じたボタン
44
63
  */
45
- export function showModalDialog(message: string | string[], options?: ShowModalDialogOptions): Promise<ModalDialogResult> {
64
+ export function showModalDialog(message: ModalDialogMessage | ModalDialogMessage[], options?: ShowModalDialogOptions): Promise<ModalDialogResult> {
46
65
  const { icon, appContext, ...dialogProps } = options ?? {};
47
66
  return new Promise((resolve) => {
48
67
  const container = document.createElement('div');
@@ -71,7 +90,7 @@ export function showModalDialog(message: string | string[], options?: ShowModalD
71
90
  * @param {Omit<ShowModalDialogOptions, 'type'>} [options]
72
91
  * @returns {Promise<ModalDialogResult>} 閉じたボタン
73
92
  */
74
- export function showInformationDialog(message: string | string[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
93
+ export function showInformationDialog(message: ModalDialogMessage | ModalDialogMessage[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
75
94
  return showModalDialog(message, {
76
95
  ...options,
77
96
  type: 'info'
@@ -85,7 +104,7 @@ export function showInformationDialog(message: string | string[], options?: Omit
85
104
  * @param {Omit<ShowModalDialogOptions, 'type'>} [options]
86
105
  * @returns {Promise<ModalDialogResult>} 閉じたボタン
87
106
  */
88
- export function showConfirmationDialog(message: string | string[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
107
+ export function showConfirmationDialog(message: ModalDialogMessage | ModalDialogMessage[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
89
108
  return showModalDialog(message, {
90
109
  ...options,
91
110
  type: 'confirm'
@@ -99,7 +118,7 @@ export function showConfirmationDialog(message: string | string[], options?: Omi
99
118
  * @param {Omit<ShowModalDialogOptions, 'type'>} [options]
100
119
  * @returns {Promise<ModalDialogResult>} 閉じたボタン
101
120
  */
102
- export function showWarningDialog(message: string | string[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
121
+ export function showWarningDialog(message: ModalDialogMessage | ModalDialogMessage[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
103
122
  return showModalDialog(message, {
104
123
  ...options,
105
124
  type: 'warn'
@@ -113,7 +132,7 @@ export function showWarningDialog(message: string | string[], options?: Omit<Sho
113
132
  * @param {Omit<ShowModalDialogOptions, 'type'>} [options]
114
133
  * @returns {Promise<ModalDialogResult>} 閉じたボタン
115
134
  */
116
- export function showErrorDialog(message: string | string[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
135
+ export function showErrorDialog(message: ModalDialogMessage | ModalDialogMessage[], options?: Omit<ShowModalDialogOptions, 'type'>): Promise<ModalDialogResult> {
117
136
  return showModalDialog(message, {
118
137
  ...options,
119
138
  type: 'error'
@@ -1,8 +1,11 @@
1
1
  import { h } from 'vue';
2
2
  import type { AppContext, ClassValue, Component, StyleValue } from 'vue';
3
3
  import OverlayBox from '@/overlay-box.vue';
4
- import { mountWindow, useWindowOwner } from '@/internal/mount-window';
5
- import type { MovableWindowContentProps, MovableWindowDragMode, MovableWindowHandle } from '@/types/movable-window';
4
+ import { mountWindow, useWindowOwner } from '@/internal/window-control';
5
+ import type { MovableWindowContentProps, MovableWindowDragMode, MovableWindowHandle } from '@/internal/window-control';
6
+
7
+ /** 開いている OverlayBox を開いた順に持つ。Esc では最後に開いたものだけを閉じる */
8
+ export const openedOverlayBoxes: symbol[] = [];
6
9
 
7
10
  /** showOverlayBox が中身のコンポーネントに props として渡す関数 */
8
11
  export type OverlayBoxContentProps = MovableWindowContentProps;
@@ -1,7 +1,25 @@
1
1
  import { h, render, shallowReactive } from 'vue';
2
2
  import type { ClassValue, StyleValue } from 'vue';
3
3
  import SnackbarContainer from '@/internal/snackbar-container.vue';
4
- import type { SnackbarDirection, SnackbarItem, SnackbarPlacement } from '@/internal/snackbar-item';
4
+
5
+ /** snackbar を表示する画面上の位置 */
6
+ export type SnackbarPlacement = 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end';
7
+
8
+ /** 同じ表示領域に並べる向き。overlap は同じ位置に重ねて新しいものを前面に出し、column は縦に積み、row は横に並べて端で折り返す */
9
+ export type SnackbarDirection = 'overlap' | 'column' | 'row';
10
+
11
+ /** 表示領域に並べる snackbar 1件分の内容 */
12
+ export interface SnackbarItem {
13
+ id: number;
14
+ message: string;
15
+ title?: string;
16
+ label?: string;
17
+ timestamp?: string;
18
+ clearable: boolean;
19
+ clearLabel: string;
20
+ class?: ClassValue;
21
+ style?: StyleValue;
22
+ }
5
23
 
6
24
  /** snackbar が閉じた理由。click はクリック、duration は表示時間の経過、clear は一括消去ボタンと closeAllSnackbars()、handle は SnackbarHandle の close() */
7
25
  export type SnackbarCloseReason = 'click' | 'duration' | 'clear' | 'handle';
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ export type { Props as HelpPopperProps, Emits as HelpPopperEmits, Slots as HelpP
9
9
  export type { Props as HourglassLoadingProps } from '@/hourglass-loading.vue';
10
10
  export type { Props as IntersectionLazyComponentProps, Emits as IntersectionLazyComponentEmits, Slots as IntersectionLazyComponentSlots } from '@/intersection-lazy-component.vue';
11
11
  export type { Props as LabelButtonProps, Slots as LabelButtonSlots } from '@/label-button.vue';
12
- export type { Props as LabelIconProps, Slots as LabelIconSlots } from '@/label-icon.vue';
12
+ export type { Props as LabelIconProps, Slots as LabelIconSlots, LabelPreset } from '@/label-icon.vue';
13
13
  export type { Props as ModalDialogProps, Emits as ModalDialogEmits, Slots as ModalDialogSlots } from '@/modal-dialog.vue';
14
14
  export type { Props as OverlayBoxProps, Emits as OverlayBoxEmits, Slots as OverlayBoxSlots } from '@/overlay-box.vue';
15
15
  export type { Props as PageSectionProps, Slots as PageSectionSlots } from '@/page-section.vue';
@@ -18,23 +18,20 @@ export type { Props as ScreenLoadingProps } from '@/screen-loading.vue';
18
18
  export type { Props as TabContentProps, Slots as TabContentSlots } from '@/tab-content.vue';
19
19
  export type { Props as TabGroupProps, Slots as TabGroupSlots } from '@/tab-group.vue';
20
20
  export type { Props as WarningPopperProps, Emits as WarningPopperEmits, Slots as WarningPopperSlots } from '@/warning-popper.vue';
21
- export { headersToCsvColumns, rowToCsvColumns } from '@/helpers/data-table-csv';
22
- export type { DataTableControlsPlacement, DataTableCsvColumn, DataTableHeader, DataTableLabels, DataTableResolvedLabels, DataTableSortContext, DataTableSortMode, DataTableValueType } from '@/types/data-table';
23
- export { closeAllFloatingComponents, showFloatingComponent, showFloatingMessage, useFloatingComponent } from '@/helpers/show-floating-component';
24
- export type { FloatingComponentContentProps, FloatingComponentHandle, ShowFloatingComponentOptions, ShowFloatingMessageOptions } from '@/helpers/show-floating-component';
25
- export { showConfirmationDialog, showErrorDialog, showInformationDialog, showModalDialog, showWarningDialog } from '@/helpers/show-modal-dialog';
26
- export type { ShowModalDialogOptions } from '@/helpers/show-modal-dialog';
27
- export type { ModalDialogButton, ModalDialogImage, ModalDialogResult, ModalDialogType } from '@/types/modal-dialog';
28
- export { closeAllOverlayBoxes, showOverlayBox, useOverlayBox } from '@/helpers/show-overlay-box';
29
- export type { OverlayBoxContentProps, OverlayBoxHandle, ShowOverlayBoxOptions } from '@/helpers/show-overlay-box';
30
- export { showScreenLoading } from '@/helpers/show-screen-loading';
31
- export type { ScreenLoadingHandle, ShowScreenLoadingOptions } from '@/helpers/show-screen-loading';
32
- export { closeAllSnackbars, showSnackbar } from '@/helpers/show-snackbar';
33
- export type { ShowSnackbarOptions, SnackbarCloseReason, SnackbarHandle } from '@/helpers/show-snackbar';
34
- export type { SnackbarDirection, SnackbarPlacement } from '@/internal/snackbar-item';
35
- export type { LabelPreset } from '@/types/label-preset';
36
- export type { MovableWindowContentProps, MovableWindowDragMode, MovableWindowHandle } from '@/types/movable-window';
37
- export type { TabContentStatus } from '@/internal/tab-group-context';
21
+ export { headersToCsvColumns, rowToCsvColumns } from '@/helpers/data-table';
22
+ export type { DataTableControlsPlacement, DataTableCsvColumn, DataTableHeader, DataTableLabels, DataTableResolvedLabels, DataTableSortContext, DataTableSortMode, DataTableValueType } from '@/helpers/data-table';
23
+ export { closeAllFloatingComponents, showFloatingComponent, showFloatingMessage, useFloatingComponent } from '@/helpers/floating-component';
24
+ export type { FloatingComponentContentProps, FloatingComponentHandle, ShowFloatingComponentOptions, ShowFloatingMessageOptions } from '@/helpers/floating-component';
25
+ export { showConfirmationDialog, showErrorDialog, showInformationDialog, showModalDialog, showWarningDialog } from '@/helpers/modal-dialog';
26
+ export type { ModalDialogButton, ModalDialogImage, ModalDialogMessage, ModalDialogResult, ModalDialogType, ShowModalDialogOptions } from '@/helpers/modal-dialog';
27
+ export { closeAllOverlayBoxes, showOverlayBox, useOverlayBox } from '@/helpers/overlay-box';
28
+ export type { OverlayBoxContentProps, OverlayBoxHandle, ShowOverlayBoxOptions } from '@/helpers/overlay-box';
29
+ export { showScreenLoading } from '@/helpers/screen-loading';
30
+ export type { ScreenLoadingHandle, ShowScreenLoadingOptions } from '@/helpers/screen-loading';
31
+ export { closeAllSnackbars, showSnackbar } from '@/helpers/snackbar';
32
+ export type { ShowSnackbarOptions, SnackbarCloseReason, SnackbarDirection, SnackbarHandle, SnackbarPlacement } from '@/helpers/snackbar';
33
+ export type { MovableWindowContentProps, MovableWindowDragMode, MovableWindowHandle } from '@/internal/window-control';
34
+ export type { TabContentStatus } from '@/internal/tab-group';
38
35
  export { vueCoreOptionsKey } from '@/helpers/vue-core-options';
39
36
  export type { DataTableOptions, VueCoreOptions } from '@/helpers/vue-core-options';
40
37
  export type { PopoverPlacement } from '@/internal/anchored-position';
@@ -67,7 +67,7 @@ DataTable の上下に置くコントロール
67
67
  import { computed } from 'vue';
68
68
  import { SvgCloudDownload, SvgFolderDownload } from '@digitalwalletcorp/vue-svg-icons';
69
69
  import Pagination from '@/internal/pagination.vue';
70
- import type { DataTableResolvedLabels } from '@/types/data-table';
70
+ import type { DataTableResolvedLabels } from '@/helpers/data-table';
71
71
 
72
72
  interface Props {
73
73
  /** ページネーションを表示するか */
@@ -50,8 +50,8 @@ import type { ClassValue, StyleValue } from 'vue';
50
50
  import CopyButton from '@/copy-button.vue';
51
51
  import { computeAnchoredPosition } from '@/internal/anchored-position';
52
52
  import MovableWindow from '@/internal/movable-window.vue';
53
- import { nextWindowOrder } from '@/internal/window-order';
54
- import type { MovableWindowDragMode } from '@/types/movable-window';
53
+ import { nextWindowOrder } from '@/internal/window-control';
54
+ import type { MovableWindowDragMode } from '@/internal/window-control';
55
55
 
56
56
  interface Props {
57
57
  /** 表示するか */
@@ -0,0 +1,118 @@
1
+ /** オブジェクト・配列を表す JSON 文字列か判定するためのパターン */
2
+ const JSON_LIKE_PATTERN = /^\s*[[{]/;
3
+
4
+ /**
5
+ * 文字列またはオブジェクトを、ダイアログやウィンドウに表示するテキストにする
6
+ * オブジェクトは 2 スペースで字下げした JSON 風のテキストにする。読みやすさを優先し、JSON として元に戻せる形にはしない
7
+ * ・JSON 文字列を値に持つ項目は、オブジェクトとして展開する
8
+ * ・文字列の値はエスケープせず、改行や引用符もそのまま出す
9
+ * ・Error は name と message、bigint は文字列、循環参照は "[Circular]" にし、undefined と関数の項目は省く
10
+ *
11
+ * @param {string | object} message
12
+ * @returns {string}
13
+ */
14
+ export function toMessageText(message: string | object): string {
15
+ if (typeof message === 'string') {
16
+ return message;
17
+ }
18
+ if (message instanceof Error) {
19
+ return String(message);
20
+ }
21
+ return formatValue(message, 0, '', []) ?? String(message);
22
+ }
23
+
24
+ /**
25
+ * オブジェクトまたは配列を表す JSON 文字列ならパースした値を、それ以外なら undefined を返す
26
+ *
27
+ * @param {string} value
28
+ * @returns {unknown}
29
+ */
30
+ function parseJsonLike(value: string): unknown {
31
+ if (!JSON_LIKE_PATTERN.test(value)) {
32
+ return undefined;
33
+ }
34
+ try {
35
+ const parsed: unknown = JSON.parse(value);
36
+ return typeof parsed === 'object' && parsed !== null ? parsed : undefined;
37
+ } catch {
38
+ return undefined;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * 値を表示用のテキストにする。JSON に出力しない値(undefined・関数・symbol)は undefined を返す
44
+ *
45
+ * @param {unknown} value
46
+ * @param {number} depth ルートを 0 とするネストの深さ
47
+ * @param {string} key 親オブジェクトでのキー。toJSON に渡す
48
+ * @param {object[]} ancestors 処理中の親オブジェクト。循環参照の検出に使う
49
+ * @returns {string | undefined}
50
+ */
51
+ function formatValue(value: unknown, depth: number, key: string, ancestors: object[]): string | undefined {
52
+ switch (typeof value) {
53
+ case 'string': {
54
+ const parsed = parseJsonLike(value);
55
+ return parsed === undefined ? `"${value}"` : formatValue(parsed, depth, key, ancestors);
56
+ }
57
+ case 'number':
58
+ case 'boolean':
59
+ return String(value);
60
+ case 'bigint':
61
+ return `"${value.toString()}"`;
62
+ case 'object': {
63
+ if (value === null) {
64
+ return 'null';
65
+ }
66
+ if (value instanceof Error) {
67
+ return `"${String(value)}"`;
68
+ }
69
+ const { toJSON } = value as { toJSON?: (key: string) => unknown };
70
+ if (typeof toJSON === 'function') {
71
+ return formatValue(toJSON.call(value, key), depth, key, ancestors);
72
+ }
73
+ if (ancestors.includes(value)) {
74
+ return '"[Circular]"';
75
+ }
76
+ ancestors.push(value);
77
+ try {
78
+ return formatContainer(value, depth, ancestors);
79
+ } finally {
80
+ ancestors.pop();
81
+ }
82
+ }
83
+ default:
84
+ return undefined;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * オブジェクトまたは配列の要素を整形して括弧で囲む
90
+ *
91
+ * @param {object} value
92
+ * @param {number} depth
93
+ * @param {object[]} ancestors
94
+ * @returns {string}
95
+ */
96
+ function formatContainer(value: object, depth: number, ancestors: object[]): string {
97
+ const isArray = Array.isArray(value);
98
+ const entries: string[] = [];
99
+ if (isArray) {
100
+ for (let i = 0; i < value.length; i++) {
101
+ entries.push(formatValue(value[i], depth + 1, String(i), ancestors) ?? 'null');
102
+ }
103
+ } else {
104
+ for (const [key, item] of Object.entries(value)) {
105
+ const formatted = formatValue(item, depth + 1, key, ancestors);
106
+ if (formatted !== undefined) {
107
+ entries.push(`"${key}": ${formatted}`);
108
+ }
109
+ }
110
+ }
111
+ const [open, close] = isArray ? ['[', ']'] : ['{', '}'];
112
+ if (entries.length === 0) {
113
+ return `${open}${close}`;
114
+ }
115
+ const indent = ' '.repeat(depth + 1);
116
+ const closeIndent = ' '.repeat(depth);
117
+ return `${open}\n${indent}${entries.join(`,\n${indent}`)}\n${closeIndent}${close}`;
118
+ }
@@ -80,7 +80,7 @@ import type { ClassValue, StyleValue } from 'vue';
80
80
  import { SvgCornerDiagonal, SvgNegativeSquaredCrossMark } from '@digitalwalletcorp/vue-svg-icons';
81
81
  import { useMovableWindow } from '@/internal/use-movable-window';
82
82
  import type { MovableWindowCorner } from '@/internal/use-movable-window';
83
- import type { MovableWindowDragMode } from '@/types/movable-window';
83
+ import type { MovableWindowDragMode } from '@/internal/window-control';
84
84
 
85
85
  interface Props {
86
86
  /** 各部位のクラスの接頭辞。利用側のコンポーネントのクラス名(dwui-overlay-box など) */
@@ -144,7 +144,7 @@
144
144
 
145
145
  <script setup lang="ts">
146
146
  import { computed, ref } from 'vue';
147
- import type { DataTableResolvedLabels } from '@/types/data-table';
147
+ import type { DataTableResolvedLabels } from '@/helpers/data-table';
148
148
  import { SvgBlackArrow, SvgChevron, SvgChevronDouble } from '@digitalwalletcorp/vue-svg-icons';
149
149
 
150
150
  interface Props {
@@ -68,7 +68,7 @@ showSnackbar から body 直下に描画して使う。
68
68
  <script setup lang="ts">
69
69
  import { computed } from 'vue';
70
70
  import { SvgWastebasket } from '@digitalwalletcorp/vue-svg-icons';
71
- import type { SnackbarDirection, SnackbarItem, SnackbarPlacement } from '@/internal/snackbar-item';
71
+ import type { SnackbarDirection, SnackbarItem, SnackbarPlacement } from '@/helpers/snackbar';
72
72
 
73
73
  interface Props {
74
74
  /** 表示する位置 */
@@ -1,6 +1,6 @@
1
1
  import { onBeforeUnmount, reactive, ref } from 'vue';
2
2
  import type { Ref } from 'vue';
3
- import type { MovableWindowDragMode } from '@/types/movable-window';
3
+ import type { MovableWindowDragMode } from '@/internal/window-control';
4
4
 
5
5
  /** リサイズで掴んでいる角 */
6
6
  export type MovableWindowCorner = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';