@digitalwalletcorp/vue-core 1.2.0 → 1.3.0

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 (188) hide show
  1. package/README.md +95 -8
  2. package/lib/accordion-fieldset.d.cts +14 -4
  3. package/lib/accordion-fieldset.d.ts +14 -4
  4. package/lib/accordion-section.d.cts +20 -10
  5. package/lib/accordion-section.d.ts +20 -10
  6. package/lib/components-2zQ2SZuY.js +26 -0
  7. package/lib/components-HaiHcseF.cjs +1 -0
  8. package/lib/components.d.cts +10 -0
  9. package/lib/components.d.ts +10 -0
  10. package/lib/copy-button.d.cts +34 -0
  11. package/lib/copy-button.d.ts +34 -0
  12. package/lib/dark-mode-selector.d.cts +32 -0
  13. package/lib/dark-mode-selector.d.ts +32 -0
  14. package/lib/data-table.d.cts +30 -0
  15. package/lib/data-table.d.ts +30 -0
  16. package/lib/help-button.d.cts +39 -0
  17. package/lib/help-button.d.ts +39 -0
  18. package/lib/help-popper.d.cts +39 -0
  19. package/lib/help-popper.d.ts +39 -0
  20. package/lib/helpers/data-table-csv.d.cts +17 -0
  21. package/lib/helpers/data-table-csv.d.ts +17 -0
  22. package/lib/helpers/show-floating-component.d.cts +82 -0
  23. package/lib/helpers/show-floating-component.d.ts +82 -0
  24. package/lib/helpers/show-modal-dialog.d.cts +73 -0
  25. package/lib/helpers/show-modal-dialog.d.ts +73 -0
  26. package/lib/helpers/show-overlay-box.d.cts +53 -0
  27. package/lib/helpers/show-overlay-box.d.ts +53 -0
  28. package/lib/helpers/show-screen-loading.d.cts +20 -0
  29. package/lib/helpers/show-screen-loading.d.ts +20 -0
  30. package/lib/helpers/show-snackbar.d.cts +47 -0
  31. package/lib/helpers/show-snackbar.d.ts +47 -0
  32. package/lib/hourglass-loading.d.cts +1 -1
  33. package/lib/hourglass-loading.d.ts +1 -1
  34. package/lib/index.cjs +1 -1
  35. package/lib/index.d.cts +34 -0
  36. package/lib/index.d.ts +34 -0
  37. package/lib/index.js +445 -18
  38. package/lib/internal/anchored-popover.d.cts +35 -0
  39. package/lib/internal/anchored-popover.d.ts +35 -0
  40. package/lib/internal/anchored-position.d.cts +50 -0
  41. package/lib/internal/anchored-position.d.ts +50 -0
  42. package/lib/internal/data-table-controls.d.cts +42 -0
  43. package/lib/internal/data-table-controls.d.ts +42 -0
  44. package/lib/internal/data-table-value.d.cts +32 -0
  45. package/lib/internal/data-table-value.d.ts +32 -0
  46. package/lib/internal/floating-component.d.cts +52 -0
  47. package/lib/internal/floating-component.d.ts +52 -0
  48. package/lib/internal/icon-popper.d.cts +32 -0
  49. package/lib/internal/icon-popper.d.ts +32 -0
  50. package/lib/internal/mount-window.d.cts +39 -0
  51. package/lib/internal/mount-window.d.ts +39 -0
  52. package/lib/internal/movable-window.d.cts +55 -0
  53. package/lib/internal/movable-window.d.ts +55 -0
  54. package/lib/internal/opened-overlay-boxes.d.cts +2 -0
  55. package/lib/internal/opened-overlay-boxes.d.ts +2 -0
  56. package/lib/internal/pagination.d.cts +22 -0
  57. package/lib/internal/pagination.d.ts +22 -0
  58. package/lib/internal/snackbar-container.d.cts +20 -0
  59. package/lib/internal/snackbar-container.d.ts +20 -0
  60. package/lib/internal/snackbar-item.d.cts +17 -0
  61. package/lib/internal/snackbar-item.d.ts +17 -0
  62. package/lib/internal/tab-group-context.d.cts +4 -2
  63. package/lib/internal/tab-group-context.d.ts +4 -2
  64. package/lib/internal/use-movable-window.d.cts +44 -0
  65. package/lib/internal/use-movable-window.d.ts +44 -0
  66. package/lib/internal/window-order.d.cts +6 -0
  67. package/lib/internal/window-order.d.ts +6 -0
  68. package/lib/intersection-lazy-component.d.cts +32 -0
  69. package/lib/intersection-lazy-component.d.ts +32 -0
  70. package/lib/label-button.d.cts +2 -2
  71. package/lib/label-button.d.ts +2 -2
  72. package/lib/label-icon.d.cts +2 -2
  73. package/lib/label-icon.d.ts +2 -2
  74. package/lib/modal-dialog.d.cts +67 -0
  75. package/lib/modal-dialog.d.ts +67 -0
  76. package/lib/nuxt.cjs +1 -1
  77. package/lib/nuxt.js +1 -1
  78. package/lib/overlay-box.d.cts +52 -0
  79. package/lib/overlay-box.d.ts +52 -0
  80. package/lib/page-section.d.cts +2 -2
  81. package/lib/page-section.d.ts +2 -2
  82. package/lib/page-title.d.cts +2 -2
  83. package/lib/page-title.d.ts +2 -2
  84. package/lib/register.cjs +1 -1
  85. package/lib/register.js +1 -1
  86. package/lib/screen-loading.d.cts +7 -0
  87. package/lib/screen-loading.d.ts +7 -0
  88. package/lib/style.css +1 -1
  89. package/lib/tab-content.d.cts +5 -5
  90. package/lib/tab-content.d.ts +5 -5
  91. package/lib/tab-group.d.cts +7 -10
  92. package/lib/tab-group.d.ts +7 -10
  93. package/lib/types/data-table.d.cts +185 -0
  94. package/lib/types/data-table.d.ts +185 -0
  95. package/lib/types/modal-dialog.d.cts +13 -0
  96. package/lib/types/modal-dialog.d.ts +13 -0
  97. package/lib/types/movable-window.d.cts +16 -0
  98. package/lib/types/movable-window.d.ts +16 -0
  99. package/lib/warning-popper.d.cts +39 -0
  100. package/lib/warning-popper.d.ts +39 -0
  101. package/lib/warning-popper.vue_vue_type_style_index_0_lang-CxVzqsbn.cjs +1 -0
  102. package/lib/warning-popper.vue_vue_type_style_index_0_lang-zt-jCsvz.js +1833 -0
  103. package/package.json +43 -16
  104. package/src/accordion-fieldset.vue +29 -19
  105. package/src/accordion-section.vue +41 -26
  106. package/src/components.ts +10 -0
  107. package/src/copy-button.vue +89 -0
  108. package/src/dark-mode-selector.vue +212 -0
  109. package/src/data-table.vue +643 -0
  110. package/src/help-button.vue +128 -0
  111. package/src/help-popper.vue +70 -0
  112. package/src/helpers/data-table-csv.ts +55 -0
  113. package/src/helpers/show-floating-component.ts +169 -0
  114. package/src/helpers/show-modal-dialog.ts +121 -0
  115. package/src/helpers/show-overlay-box.ts +106 -0
  116. package/src/helpers/show-screen-loading.ts +37 -0
  117. package/src/helpers/show-snackbar.ts +153 -0
  118. package/src/hourglass-loading.vue +1 -1
  119. package/src/index.ts +34 -0
  120. package/src/internal/anchored-popover.vue +192 -0
  121. package/src/internal/anchored-position.ts +135 -0
  122. package/src/internal/data-table-controls.vue +203 -0
  123. package/src/internal/data-table-value.ts +99 -0
  124. package/src/internal/floating-component.vue +202 -0
  125. package/src/internal/icon-popper.vue +185 -0
  126. package/src/internal/mount-window.ts +110 -0
  127. package/src/internal/movable-window.vue +315 -0
  128. package/src/internal/opened-overlay-boxes.ts +2 -0
  129. package/src/internal/pagination.vue +325 -0
  130. package/src/internal/snackbar-container.vue +258 -0
  131. package/src/internal/snackbar-item.ts +20 -0
  132. package/src/internal/tab-group-context.ts +4 -2
  133. package/src/internal/use-movable-window.ts +208 -0
  134. package/src/internal/window-order.ts +11 -0
  135. package/src/intersection-lazy-component.vue +84 -0
  136. package/src/label-button.vue +37 -3
  137. package/src/label-icon.vue +2 -2
  138. package/src/modal-dialog.vue +287 -0
  139. package/src/overlay-box.vue +218 -0
  140. package/src/page-section.vue +7 -7
  141. package/src/page-title.vue +5 -5
  142. package/src/screen-loading.vue +90 -0
  143. package/src/tab-content.vue +17 -16
  144. package/src/tab-group.vue +55 -46
  145. package/src/types/data-table.ts +196 -0
  146. package/src/types/modal-dialog.ts +16 -0
  147. package/src/types/movable-window.ts +18 -0
  148. package/src/warning-popper.vue +70 -0
  149. package/lib/accordion-fieldset.cjs +0 -1
  150. package/lib/accordion-fieldset.js +0 -4
  151. package/lib/accordion-fieldset.vue_vue_type_style_index_0_lang-n-IZxUiu.js +0 -66
  152. package/lib/accordion-fieldset.vue_vue_type_style_index_0_lang-t9NqmoZW.cjs +0 -1
  153. package/lib/accordion-section.cjs +0 -1
  154. package/lib/accordion-section.js +0 -4
  155. package/lib/accordion-section.vue_vue_type_style_index_0_lang-CFDdUEnn.cjs +0 -1
  156. package/lib/accordion-section.vue_vue_type_style_index_0_lang-Gvjjx02P.js +0 -78
  157. package/lib/components-CNOeuZPu.cjs +0 -1
  158. package/lib/components-DBK8NUBh.js +0 -24
  159. package/lib/hourglass-loading.cjs +0 -1
  160. package/lib/hourglass-loading.js +0 -4
  161. package/lib/hourglass-loading.vue_vue_type_style_index_0_lang-C72UVA9W.cjs +0 -1
  162. package/lib/hourglass-loading.vue_vue_type_style_index_0_lang-DkUGIxQ2.js +0 -22
  163. package/lib/label-button.cjs +0 -1
  164. package/lib/label-button.js +0 -4
  165. package/lib/label-button.vue_vue_type_script_setup_true_lang-BwVOxaJP.cjs +0 -1
  166. package/lib/label-button.vue_vue_type_script_setup_true_lang-DorC4pKz.js +0 -44
  167. package/lib/label-icon.cjs +0 -1
  168. package/lib/label-icon.js +0 -4
  169. package/lib/label-icon.vue_vue_type_style_index_0_lang-D9Cimu20.cjs +0 -1
  170. package/lib/label-icon.vue_vue_type_style_index_0_lang-me52HE2V.js +0 -38
  171. package/lib/page-section.cjs +0 -1
  172. package/lib/page-section.js +0 -4
  173. package/lib/page-section.vue_vue_type_style_index_0_lang-DEAkTLxd.cjs +0 -1
  174. package/lib/page-section.vue_vue_type_style_index_0_lang-DpVQe_rV.js +0 -54
  175. package/lib/page-title.cjs +0 -1
  176. package/lib/page-title.js +0 -4
  177. package/lib/page-title.vue_vue_type_style_index_0_lang-BqIsIks5.cjs +0 -1
  178. package/lib/page-title.vue_vue_type_style_index_0_lang-ChZot85K.js +0 -36
  179. package/lib/tab-content.cjs +0 -1
  180. package/lib/tab-content.js +0 -4
  181. package/lib/tab-content.vue_vue_type_style_index_0_lang-BeCi7Xkp.cjs +0 -1
  182. package/lib/tab-content.vue_vue_type_style_index_0_lang-CcQLHmIF.js +0 -44
  183. package/lib/tab-group.cjs +0 -1
  184. package/lib/tab-group.js +0 -4
  185. package/lib/tab-group.vue_vue_type_style_index_0_lang-C84mDEOC.js +0 -103
  186. package/lib/tab-group.vue_vue_type_style_index_0_lang-CMaufRJV.cjs +0 -1
  187. package/lib/use-shrinkable-CS2bmsJJ.js +0 -17
  188. package/lib/use-shrinkable-Cu9JQZll.cjs +0 -1
@@ -0,0 +1,218 @@
1
+ <!--
2
+ オーバーレイボックス
3
+ 画面全体に暗幕を掛け、その上に見出しと閉じるボタンの付いたウィンドウを表示する。
4
+ 閉じるボタン・Esc・暗幕のクリック(closeOnBackdrop)で閉じる。ウィンドウはドラッグで移動でき、右下のつまみでリサイズできる。
5
+ 中に置いた要素が body 直下に描画するツールチップやドロップダウンを隠さないよう、<dialog> の最前面表示ではなく z-index で前面に出す。
6
+ FloatingComponent とは開いた順に重なり、後から開いたものが前面に出る。
7
+ -->
8
+ <template>
9
+ <Transition
10
+ name="dwui-overlay-box-fade"
11
+ @after-leave="onAfterLeaveOverlayBox"
12
+ >
13
+ <div
14
+ v-if="open"
15
+ class="dwui-overlay-box"
16
+ :style="{ '--dwui-order-window': order }"
17
+ >
18
+ <div
19
+ class="dwui-overlay-box-backdrop"
20
+ @click="onClickBackdrop"
21
+ />
22
+ <MovableWindow
23
+ ref="refWindow"
24
+ class="dwui-overlay-box-container"
25
+ name="dwui-overlay-box"
26
+ tabindex="-1"
27
+ :drag-mode="props.dragMode"
28
+ :loading="props.loading"
29
+ :close-label="props.closeLabel"
30
+ clamp-bottom
31
+ @keydown="onKeydownWindow"
32
+ @emit:close="onCloseWindow"
33
+ >
34
+ <template #title>
35
+ <slot name="title">
36
+ {{ props.title }}
37
+ </slot>
38
+ </template>
39
+ <slot />
40
+ </MovableWindow>
41
+ </div>
42
+ </Transition>
43
+ </template>
44
+
45
+ <script setup lang="ts">
46
+ import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
47
+ import MovableWindow from '@/internal/movable-window.vue';
48
+ import { openedOverlayBoxes } from '@/internal/opened-overlay-boxes';
49
+ import { nextWindowOrder } from '@/internal/window-order';
50
+ import type { MovableWindowDragMode } from '@/types/movable-window';
51
+
52
+ export interface Props {
53
+ /** 見出し。title スロットで差し替えられる */
54
+ title?: string;
55
+ /** ドラッグで移動するときに掴む範囲。body はウィンドウ全体、header は見出しだけ。未指定なら移動できない */
56
+ dragMode?: MovableWindowDragMode;
57
+ /** 暗幕のクリックで閉じる */
58
+ closeOnBackdrop?: boolean;
59
+ /** ウィンドウに暗幕とスピナーを重ね、中身を操作できなくする */
60
+ loading?: boolean;
61
+ /** 閉じるボタンの読み上げ名 */
62
+ closeLabel?: string;
63
+ }
64
+ const props = withDefaults(defineProps<Props>(), {
65
+ title: undefined,
66
+ dragMode: undefined,
67
+ closeOnBackdrop: false,
68
+ loading: false,
69
+ closeLabel: 'Close'
70
+ });
71
+
72
+ export interface Emits {
73
+ /** 閉じるアニメーションが終わり、ボックスが取り除かれた */
74
+ (e: 'emit:close'): void;
75
+ }
76
+ const emit = defineEmits<Emits>();
77
+
78
+ export interface Slots {
79
+ /** 見出し */
80
+ title?(): unknown;
81
+ /** ウィンドウに表示する中身 */
82
+ default?(): unknown;
83
+ }
84
+ defineSlots<Slots>();
85
+
86
+ /** 表示するか。閉じる操作で false になる */
87
+ const open = defineModel<boolean>('open', { default: false });
88
+
89
+ const refWindow = ref<InstanceType<typeof MovableWindow>>();
90
+ const order = ref(0);
91
+
92
+ const boxKey = Symbol('dwui-overlay-box');
93
+ let previousFocus: HTMLElement | null = null;
94
+
95
+ const onClickBackdrop = (): void => {
96
+ if (props.closeOnBackdrop) {
97
+ open.value = false;
98
+ }
99
+ };
100
+
101
+ const onCloseWindow = (): void => {
102
+ open.value = false;
103
+ };
104
+
105
+ /**
106
+ * ウィンドウにフォーカスがある間、Esc で閉じる。
107
+ * 中に置いた要素が dispatchEvent で発行した Escape、IME の変換を取り消す Esc、
108
+ * 中に置いた <dialog> に向けた Esc では閉じない
109
+ */
110
+ const onKeydownWindow = (event: KeyboardEvent): void => {
111
+ if (event.key !== 'Escape' || !event.isTrusted || event.isComposing) {
112
+ return;
113
+ }
114
+ if (event.target instanceof Element && event.target.closest('dialog')) {
115
+ return;
116
+ }
117
+ // テンプレートで box の中に置いた box の Esc は外側にもバブルするため、最後に開いた box だけが閉じる
118
+ if (openedOverlayBoxes.at(-1) === boxKey) {
119
+ open.value = false;
120
+ }
121
+ };
122
+
123
+ const onAfterLeaveOverlayBox = (): void => {
124
+ emit('emit:close');
125
+ };
126
+
127
+ const removeFromOpenedBoxes = (): void => {
128
+ const index = openedOverlayBoxes.indexOf(boxKey);
129
+ if (0 <= index) {
130
+ openedOverlayBoxes.splice(index, 1);
131
+ }
132
+ };
133
+
134
+ const activate = (): void => {
135
+ order.value = nextWindowOrder();
136
+ const movable = refWindow.value;
137
+ const rect = movable?.element?.getBoundingClientRect();
138
+ if (movable) {
139
+ movable.position.x = (window.innerWidth - (rect?.width || 0)) / 2;
140
+ // 画面より高いときに見出しが上に隠れて掴めなくならないよう、上端は画面内に収める
141
+ movable.position.y = Math.max(0, (window.innerHeight - (rect?.height || 0)) / 2);
142
+ }
143
+ previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
144
+ movable?.element?.focus();
145
+ openedOverlayBoxes.push(boxKey);
146
+ };
147
+
148
+ const deactivate = (): void => {
149
+ refWindow.value?.teardown();
150
+ removeFromOpenedBoxes();
151
+ if (previousFocus?.isConnected) {
152
+ previousFocus.focus();
153
+ }
154
+ previousFocus = null;
155
+ };
156
+
157
+ onMounted(() => {
158
+ if (open.value) {
159
+ activate();
160
+ }
161
+ });
162
+
163
+ onBeforeUnmount(() => {
164
+ removeFromOpenedBoxes();
165
+ });
166
+
167
+ watch(open, (newValue) => {
168
+ if (newValue) {
169
+ activate();
170
+ } else {
171
+ deactivate();
172
+ }
173
+ }, { flush: 'post' });
174
+ </script>
175
+
176
+ <style>
177
+ :where(html:has(.dwui-overlay-box), html:has(.dwui-overlay-box) > body) {
178
+ overflow: hidden;
179
+ }
180
+
181
+ :where(.dwui-overlay-box) {
182
+ position: fixed;
183
+ inset: 0;
184
+ z-index: calc(var(--dwui-z-index-overlay-box, 5000) + var(--dwui-order-window, 0));
185
+ }
186
+
187
+ :where(.dwui-overlay-box-backdrop) {
188
+ position: absolute;
189
+ inset: 0;
190
+ background: var(--dwui-background-overlay-box-backdrop, light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.5)));
191
+ }
192
+
193
+ :where(.dwui-overlay-box-container) {
194
+ --dwui-border-color-movable-window: var(--dwui-border-color-overlay-box, light-dark(#8f8f8f, #6b6f76));
195
+ --dwui-radius-movable-window: var(--dwui-radius-overlay-box, 4px);
196
+ --dwui-background-movable-window: var(--dwui-background-overlay-box, Canvas);
197
+ --dwui-color-text-movable-window: var(--dwui-color-text-overlay-box, CanvasText);
198
+ --dwui-box-shadow-movable-window: var(--dwui-box-shadow-overlay-box, 0 2px 8px rgba(0, 0, 0, 0.33));
199
+ --dwui-padding-movable-window-header: var(--dwui-padding-overlay-box-header, 0.17em 0.33em);
200
+ --dwui-background-movable-window-header: var(--dwui-background-overlay-box-header, transparent);
201
+ --dwui-color-text-movable-window-header: var(--dwui-color-text-overlay-box-header, inherit);
202
+ --dwui-background-movable-window-close-button-hover: var(--dwui-background-overlay-box-close-button-hover, light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.12)));
203
+ --dwui-padding-movable-window-body: var(--dwui-padding-overlay-box-body, 0.4em);
204
+ --dwui-color-text-movable-window-resizer: var(--dwui-color-text-overlay-box-resizer, GrayText);
205
+ --dwui-background-movable-window-loading: var(--dwui-background-overlay-box-loading, light-dark(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.4)));
206
+ --dwui-size-movable-window-spinner: var(--dwui-size-overlay-box-spinner, 48px);
207
+ --dwui-border-color-movable-window-spinner: var(--dwui-border-color-overlay-box-spinner, light-dark(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.2)));
208
+ --dwui-border-color-movable-window-spinner-accent: var(--dwui-border-color-overlay-box-spinner-accent, light-dark(rgba(47, 90, 74, 0.8), rgba(140, 200, 170, 0.8)));
209
+ }
210
+
211
+ :where(.dwui-overlay-box-fade-enter-active, .dwui-overlay-box-fade-leave-active) {
212
+ transition: opacity 0.25s ease;
213
+ }
214
+
215
+ :where(.dwui-overlay-box-fade-enter-from, .dwui-overlay-box-fade-leave-to) {
216
+ opacity: 0;
217
+ }
218
+ </style>
@@ -36,7 +36,7 @@ import LabelIcon from '@/label-icon.vue';
36
36
  /** 見出しのアイコンとして選べるもの */
37
37
  type PageSectionIcon = 'diamond' | 'circle' | 'square' | 'pushpin' | 'round-pushpin';
38
38
 
39
- interface Props {
39
+ export interface Props {
40
40
  /** 見出しの文字。未指定なら見出しを表示しない */
41
41
  title?: string;
42
42
  /** 見出しのアイコン。これ以外のアイコンは#iconスロットで渡す デフォルト 'diamond' */
@@ -54,7 +54,7 @@ const props = withDefaults(defineProps<Props>(), {
54
54
  icon: 'diamond'
55
55
  });
56
56
 
57
- interface Slots {
57
+ export interface Slots {
58
58
  /** 見出しの文字の前に表示するアイコン。iconより優先する */
59
59
  icon?(): unknown;
60
60
  default?(): unknown;
@@ -85,19 +85,19 @@ const presetIcon = computed((): { component: Component; props: Record<string, un
85
85
  <style>
86
86
  :where(.dwui-page-section) {
87
87
  display: block;
88
- margin: 4px 0 8px;
89
- padding-top: 2px;
90
- font-size: var(--dwui-font-size-page-section, 12px);
88
+ margin: 0.33em 0 0.67em;
89
+ padding-top: 0.17em;
90
+ font-size: var(--dwui-font-size-page-section, inherit);
91
91
  font-weight: 500;
92
92
  }
93
93
 
94
94
  :where(.dwui-page-section-title) {
95
95
  display: flex;
96
96
  align-items: center;
97
- font-size: var(--dwui-font-size-page-section-title, 14px);
97
+ font-size: var(--dwui-font-size-page-section-title, 1.17em);
98
98
  }
99
99
 
100
100
  :where(.dwui-page-section-content) {
101
- margin: 8px 0 8px 16px;
101
+ margin: 0.67em 0 0.67em 1.33em;
102
102
  }
103
103
  </style>
@@ -25,13 +25,13 @@
25
25
  <script setup lang="ts">
26
26
  import LabelIcon from '@/label-icon.vue';
27
27
 
28
- interface Props {
28
+ export interface Props {
29
29
  /** タイトルの文字 */
30
30
  title: string;
31
31
  }
32
32
  const props = defineProps<Props>();
33
33
 
34
- interface Slots {
34
+ export interface Slots {
35
35
  /** タイトルの文字の前に表示するアイコン */
36
36
  icon?(): unknown;
37
37
  /** タイトルバーの右側に表示する内容 */
@@ -46,11 +46,11 @@ const slots = defineSlots<Slots>();
46
46
  align-items: center;
47
47
  justify-content: space-between;
48
48
  width: var(--dwui-width-page-title, auto);
49
- padding: 4px;
49
+ padding: 0.33em;
50
50
  border-radius: 4px;
51
- background: var(--dwui-background-page-title, linear-gradient(#323232 0%, rgb(32, 32, 31) 25%, rgb(32, 32, 31) 75%, #323232 100%));
51
+ background: var(--dwui-background-page-title, linear-gradient(light-dark(#323232, #3c3f45) 0%, light-dark(rgb(32, 32, 31), #2b2d31) 25%, light-dark(rgb(32, 32, 31), #2b2d31) 75%, light-dark(#323232, #3c3f45) 100%));
52
52
  color: var(--dwui-color-text-page-title, rgb(220, 220, 220));
53
- font-size: var(--dwui-font-size-page-title, 14px);
53
+ font-size: var(--dwui-font-size-page-title, 1.17em);
54
54
  font-weight: var(--dwui-font-weight-page-title, normal);
55
55
  }
56
56
  </style>
@@ -0,0 +1,90 @@
1
+ <!--
2
+ 画面全体を覆うローディング。
3
+ loading が true の間は <dialog> をモーダルで開き、暗幕とスピナーを表示して画面の操作を受け付けなくする。
4
+ Esc キーでは閉じない。
5
+ -->
6
+ <template>
7
+ <dialog
8
+ ref="refDialog"
9
+ class="dwui-screen-loading"
10
+ closedby="none"
11
+ @cancel.prevent
12
+ >
13
+ <div class="dwui-screen-loading-spinner" />
14
+ </dialog>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
19
+
20
+ export interface Props {
21
+ /** 読み込み中か */
22
+ loading: boolean;
23
+ }
24
+ const props = defineProps<Props>();
25
+
26
+ const refDialog = ref<HTMLDialogElement | null>(null);
27
+
28
+ const open = () => {
29
+ const dialog = refDialog.value;
30
+ if (dialog && !dialog.open) {
31
+ dialog.showModal();
32
+ }
33
+ };
34
+
35
+ const close = () => {
36
+ const dialog = refDialog.value;
37
+ if (dialog?.open) {
38
+ dialog.close();
39
+ }
40
+ };
41
+
42
+ onMounted(() => {
43
+ if (props.loading) {
44
+ open();
45
+ }
46
+ });
47
+
48
+ onBeforeUnmount(() => {
49
+ close();
50
+ });
51
+
52
+ watch(() => props.loading, (newValue) => {
53
+ if (newValue) {
54
+ open();
55
+ } else {
56
+ close();
57
+ }
58
+ }, { flush: 'post' });
59
+ </script>
60
+
61
+ <style>
62
+ :where(.dwui-screen-loading) {
63
+ padding: 0;
64
+ border: none;
65
+ outline: none;
66
+ background-color: transparent;
67
+ background-image: none;
68
+ overflow: visible;
69
+ }
70
+
71
+ :where(.dwui-screen-loading::backdrop) {
72
+ background: var(--dwui-background-screen-loading, light-dark(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.5)));
73
+ }
74
+
75
+ :where(.dwui-screen-loading-spinner) {
76
+ box-sizing: border-box;
77
+ width: var(--dwui-size-screen-loading-spinner, 100px);
78
+ height: var(--dwui-size-screen-loading-spinner, 100px);
79
+ border: 8px solid var(--dwui-border-color-screen-loading-spinner, light-dark(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.2)));
80
+ border-left-color: var(--dwui-border-color-screen-loading-spinner-accent, light-dark(rgba(47, 90, 74, 0.8), rgba(140, 200, 170, 0.8)));
81
+ border-radius: 50%;
82
+ animation: dwui-screen-loading-spin 1.1s linear infinite;
83
+ }
84
+
85
+ @keyframes dwui-screen-loading-spin {
86
+ to {
87
+ transform: rotate(360deg);
88
+ }
89
+ }
90
+ </style>
@@ -4,12 +4,13 @@ TabGroupの中に置くタブ1つ分の中身
4
4
  <template>
5
5
  <div
6
6
  v-if="!props.disabled"
7
+ :id="context ? `${context.groupName}-${props.tabId}-panel` : undefined"
7
8
  class="dwui-tab-content"
8
- :aria-label="props.labelId"
9
- :aria-checked="selected ? 'true' : 'false'"
10
- :aria-description="props.description"
9
+ role="tabpanel"
10
+ :aria-labelledby="context ? `${context.groupName}-${props.tabId}` : undefined"
11
11
  :aria-busy="loading ? 'true' : undefined"
12
- :data-test-tab-content="props.labelId"
12
+ :hidden="!selected"
13
+ :data-test-tab-content="props.tabId"
13
14
  >
14
15
  <slot
15
16
  :activated="activated"
@@ -38,12 +39,12 @@ import type { ClassValue, Slot, StyleValue } from 'vue';
38
39
  import { tabGroupContextKey } from '@/internal/tab-group-context';
39
40
  import type { TabContentStatus } from '@/internal/tab-group-context';
40
41
 
41
- // labelId・description・header*・status・#iconは、TabGroupが見出しを描画するために読む
42
- interface Props {
43
- /** タブを識別するID。TabGroupのselectedTabLabelIdに渡す値 */
44
- labelId: string;
42
+ // tabId・label・header*・status・#iconは、TabGroupが見出しを描画するために読む
43
+ export interface Props {
44
+ /** タブを識別するID。TabGroupのselectedTabIdに渡す値 */
45
+ tabId: string;
45
46
  /** タブの見出しの文字 */
46
- description: string;
47
+ label: string;
47
48
  /** trueの場合、タブを選べなくし、中身も描画しない */
48
49
  disabled?: boolean;
49
50
  /** タブの見出しの状態。見出しの色が変わる */
@@ -55,7 +56,7 @@ interface Props {
55
56
  }
56
57
  const props = defineProps<Props>();
57
58
 
58
- interface Slots {
59
+ export interface Slots {
59
60
  /** タブの見出しの文字の前に表示するアイコン */
60
61
  icon?(): unknown;
61
62
  /**
@@ -80,7 +81,7 @@ const loading = ref(false);
80
81
  const loadingSlot = (): Slot | undefined => context?.loadingSlot();
81
82
 
82
83
  // 表示の切り替えは初期描画から効かせるため、マウントを待たない
83
- const selected = computed((): boolean => context?.activeLabelId.value === props.labelId);
84
+ const selected = computed((): boolean => context?.activeTabId.value === props.tabId);
84
85
 
85
86
  const activated = computed((): boolean => !!context?.mounted.value && selected.value);
86
87
 
@@ -95,7 +96,7 @@ const setLoading = (value: boolean) => {
95
96
  </script>
96
97
 
97
98
  <style>
98
- :where(.dwui-tab-content[aria-checked='false']) {
99
+ :where(.dwui-tab-content[hidden]) {
99
100
  display: none;
100
101
  }
101
102
 
@@ -103,7 +104,7 @@ const setLoading = (value: boolean) => {
103
104
  display: block;
104
105
  /* 読み込み中の覆いを中身の範囲に重ねる基準にする */
105
106
  position: relative;
106
- padding: 4px 8px;
107
+ padding: 0.33em 0.67em;
107
108
  overflow: hidden;
108
109
  /* 全幅を横断すると速度が出てカクつくため、既定は固定の移動量とease-outとフェードでスライドインする */
109
110
  animation: dwui-tab-slide-in var(--dwui-duration-tab-slide, 0.35s) var(--dwui-easing-tab-slide, cubic-bezier(0.22, 1, 0.36, 1));
@@ -116,14 +117,14 @@ const setLoading = (value: boolean) => {
116
117
  display: flex;
117
118
  align-items: center;
118
119
  justify-content: center;
119
- background: var(--dwui-overlay-color-loading, rgba(0, 0, 0, 0.25));
120
+ background: var(--dwui-overlay-color-loading, light-dark(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.45)));
120
121
  }
121
122
 
122
123
  :where(.dwui-tab-loading-spinner) {
123
124
  width: var(--dwui-size-loading-spinner, 40px);
124
125
  height: var(--dwui-size-loading-spinner, 40px);
125
- border: 4px solid var(--dwui-border-color-loading-spinner-track, rgba(255, 255, 255, 0.4));
126
- border-top-color: var(--dwui-border-color-loading-spinner, #ffffff);
126
+ border: 4px solid var(--dwui-border-color-loading-spinner, rgba(255, 255, 255, 0.4));
127
+ border-top-color: var(--dwui-border-color-loading-spinner-accent, #ffffff);
127
128
  border-radius: 50%;
128
129
  animation: dwui-tab-loading-spin 0.8s linear infinite;
129
130
  }