nuxt-hs-ui 2.12.7 → 4.0.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 (131) hide show
  1. package/README.md +202 -14
  2. package/dist/module.d.mts +3 -4
  3. package/dist/module.json +9 -6
  4. package/dist/module.mjs +109 -99
  5. package/dist/runtime/assets/flatpickr-dark.css +1 -1
  6. package/dist/runtime/assets/main.css +1 -0
  7. package/dist/runtime/assets/tabulator-custom.css +1 -1
  8. package/dist/runtime/components/form/_select/hidden-item-toggle.vue +28 -0
  9. package/dist/runtime/components/form/_select/hidden-item-toggle.vue.d.ts +10 -0
  10. package/dist/runtime/components/form/_select/item-container.vue +63 -0
  11. package/dist/runtime/components/form/_select/item-container.vue.d.ts +19 -0
  12. package/dist/runtime/components/form/_select/item-label.vue +31 -0
  13. package/dist/runtime/components/form/_select/item-label.vue.d.ts +13 -0
  14. package/dist/runtime/components/form/_select/item-row.vue +62 -0
  15. package/dist/runtime/components/form/_select/item-row.vue.d.ts +34 -0
  16. package/dist/runtime/components/form/btn-line-loading.vue +62 -81
  17. package/dist/runtime/components/form/btn-line-loading.vue.d.ts +14 -0
  18. package/dist/runtime/components/form/btn.vue +411 -494
  19. package/dist/runtime/components/form/btn.vue.d.ts +0 -0
  20. package/dist/runtime/components/form/check-box.vue +200 -315
  21. package/dist/runtime/components/form/check-box.vue.d.ts +71 -0
  22. package/dist/runtime/components/form/check-list.vue +234 -364
  23. package/dist/runtime/components/form/check-list.vue.d.ts +99 -0
  24. package/dist/runtime/components/form/combo-box.vue +340 -0
  25. package/dist/runtime/components/form/combo-box.vue.d.ts +69 -0
  26. package/dist/runtime/components/form/datepicker.vue +717 -883
  27. package/dist/runtime/components/form/datepicker.vue.d.ts +122 -0
  28. package/dist/runtime/components/form/input-frame.vue +174 -258
  29. package/dist/runtime/components/form/input-frame.vue.d.ts +88 -0
  30. package/dist/runtime/components/form/radio.vue +451 -614
  31. package/dist/runtime/components/form/radio.vue.d.ts +62 -0
  32. package/dist/runtime/components/form/select-img-icon.vue +38 -53
  33. package/dist/runtime/components/form/select-img-icon.vue.d.ts +15 -0
  34. package/dist/runtime/components/form/select.vue +733 -579
  35. package/dist/runtime/components/form/select.vue.d.ts +63 -0
  36. package/dist/runtime/components/form/text-box.vue +266 -365
  37. package/dist/runtime/components/form/text-box.vue.d.ts +105 -0
  38. package/dist/runtime/components/form/textarea.vue +338 -421
  39. package/dist/runtime/components/form/textarea.vue.d.ts +98 -0
  40. package/dist/runtime/components/form/value-box.vue +512 -641
  41. package/dist/runtime/components/form/value-box.vue.d.ts +128 -0
  42. package/dist/runtime/components/interactive/alert.vue +49 -113
  43. package/dist/runtime/components/interactive/alert.vue.d.ts +30 -0
  44. package/dist/runtime/components/interactive/block-loading.vue +91 -119
  45. package/dist/runtime/components/interactive/block-loading.vue.d.ts +22 -0
  46. package/dist/runtime/components/interactive/dialog.vue +252 -407
  47. package/dist/runtime/components/interactive/dialog.vue.d.ts +3 -0
  48. package/dist/runtime/components/interactive/modal-bg.vue +72 -82
  49. package/dist/runtime/components/interactive/modal-bg.vue.d.ts +11 -0
  50. package/dist/runtime/components/interactive/modal.vue +121 -169
  51. package/dist/runtime/components/interactive/modal.vue.d.ts +38 -0
  52. package/dist/runtime/components/interactive/toast.vue +164 -206
  53. package/dist/runtime/components/interactive/toast.vue.d.ts +3 -0
  54. package/dist/runtime/components/interactive/window-loader.vue +61 -84
  55. package/dist/runtime/components/interactive/window-loader.vue.d.ts +3 -0
  56. package/dist/runtime/components/layout/accordion-down.vue +72 -0
  57. package/dist/runtime/components/layout/accordion-down.vue.d.ts +26 -0
  58. package/dist/runtime/components/layout/accordion.vue +47 -78
  59. package/dist/runtime/components/layout/accordion.vue.d.ts +22 -0
  60. package/dist/runtime/components/layout/aspect-box.vue +29 -58
  61. package/dist/runtime/components/layout/aspect-box.vue.d.ts +29 -0
  62. package/dist/runtime/components/layout/card-item.vue +148 -193
  63. package/dist/runtime/components/layout/card-item.vue.d.ts +0 -0
  64. package/dist/runtime/components/layout/card.vue +27 -42
  65. package/dist/runtime/components/layout/card.vue.d.ts +23 -0
  66. package/dist/runtime/components/layout/container.vue +25 -40
  67. package/dist/runtime/components/layout/container.vue.d.ts +35 -0
  68. package/dist/runtime/components/layout/divider-h.vue +30 -50
  69. package/dist/runtime/components/layout/divider-h.vue.d.ts +18 -0
  70. package/dist/runtime/components/misc/breadcrumb.vue +47 -95
  71. package/dist/runtime/components/misc/breadcrumb.vue.d.ts +22 -0
  72. package/dist/runtime/components/misc/tabulator.vue +122 -190
  73. package/dist/runtime/components/misc/tabulator.vue.d.ts +28 -0
  74. package/dist/runtime/components/misc/view-name-display.vue +53 -68
  75. package/dist/runtime/components/misc/view-name-display.vue.d.ts +14 -0
  76. package/dist/runtime/components/test.vue +13 -0
  77. package/dist/runtime/components/test.vue.d.ts +3 -0
  78. package/dist/runtime/composables/test.d.ts +8 -0
  79. package/dist/runtime/composables/test.js +12 -0
  80. package/dist/runtime/composables/use-hs-dialog.d.ts +3 -20
  81. package/dist/runtime/composables/use-hs-dialog.js +3 -9
  82. package/dist/runtime/composables/use-hs-is-mobile.d.ts +8 -2
  83. package/dist/runtime/composables/use-hs-is-mobile.js +43 -25
  84. package/dist/runtime/composables/use-hs-misc.d.ts +8 -38
  85. package/dist/runtime/composables/use-hs-misc.js +9 -61
  86. package/dist/runtime/composables/use-hs-modal.js +1 -3
  87. package/dist/runtime/composables/use-hs-multi-lang.d.ts +23 -40
  88. package/dist/runtime/composables/use-hs-multi-lang.js +30 -74
  89. package/dist/runtime/composables/use-hs-scroll-lock.d.ts +1 -1
  90. package/dist/runtime/composables/use-hs-scroll-lock.js +2 -1
  91. package/dist/runtime/composables/use-hs-toast.d.ts +2 -2
  92. package/dist/runtime/composables/use-hs-toast.js +12 -4
  93. package/dist/runtime/composables/use-pinia.d.ts +1 -0
  94. package/dist/runtime/composables/use-pinia.js +2 -0
  95. package/dist/runtime/plugin.d.ts +2 -0
  96. package/dist/runtime/plugin.js +4 -0
  97. package/dist/runtime/server/tsconfig.json +3 -3
  98. package/dist/runtime/types/dialog.d.ts +11 -20
  99. package/dist/runtime/types/dialog.js +2 -1
  100. package/dist/runtime/types/flatpickr/default.js +2 -23
  101. package/dist/runtime/types/flatpickr/ja.js +3 -37
  102. package/dist/runtime/types/toast.d.ts +1 -1
  103. package/dist/runtime/utils/dayjs.d.ts +8 -6
  104. package/dist/runtime/utils/dayjs.js +12 -5
  105. package/dist/runtime/utils/modal.d.ts +9 -28
  106. package/dist/runtime/utils/modal.js +7 -36
  107. package/dist/runtime/utils/multi-lang-object.d.ts +2 -2
  108. package/dist/runtime/utils/multi-lang-object.js +1 -5
  109. package/dist/runtime/utils/multi-lang.js +12 -22
  110. package/dist/runtime/utils/object.js +1 -1
  111. package/dist/runtime/utils/select-item.d.ts +3 -1
  112. package/dist/runtime/utils/stop-watch.js +6 -4
  113. package/dist/runtime/utils/string.js +4 -4
  114. package/dist/runtime/utils/tabulator.d.ts +1 -42
  115. package/dist/runtime/utils/tabulator.js +2 -99
  116. package/dist/runtime/utils/theme.d.ts +20 -20
  117. package/dist/runtime/utils/theme.js +180 -30
  118. package/dist/runtime/utils/tv.d.ts +1 -101
  119. package/dist/runtime/utils/tv.js +0 -22
  120. package/dist/types.d.mts +3 -1
  121. package/package.json +61 -119
  122. package/dist/module.cjs +0 -5
  123. package/dist/module.d.ts +0 -16
  124. package/dist/runtime/assets/vue-select.css +0 -1
  125. package/dist/runtime/components/misc/view-name-display-target.vue +0 -39
  126. package/dist/runtime/plugin/v-select.d.ts +0 -2
  127. package/dist/runtime/plugin/v-select.js +0 -5
  128. package/dist/runtime/style.css +0 -22
  129. package/dist/runtime/tailwind.css +0 -78
  130. package/dist/runtime/types/app.config.d.ts +0 -5
  131. package/dist/types.d.ts +0 -1
@@ -1,590 +1,744 @@
1
- <script setup lang="ts" generic="IdType extends string|number">
2
- /* ----------------------------------------------------------------------------
3
- // src\runtime\components\form\select.vue
4
- // ----------------------------------------------------------------------------
5
- // Select
6
- // SelectSelect
7
- ----------------------------------------------------------------------------- */
8
-
9
- // [ tailwind ]
10
- // [ NUXT ]
11
- import { reactive, ref, watch, computed, useId, nextTick } from "#imports";
12
-
13
- // import { createPopper } from "@popperjs/core";
14
-
15
- // [ utils ]
16
- import type { ClassType } from "../../utils/class-style";
17
- import type { SelectItem } from "../../utils/select-item";
18
- import { useDisplayList, type DisplaySelectItem } from "../../utils/select";
19
- import { ObjectCopy } from "../../utils/object";
20
-
21
- import type { MultiLang } from "../../utils/multi-lang";
22
- // [ composables ]
23
- import { useHsFocus } from "../../composables/use-hs-focus";
24
- import { useHsMultiLang } from "../../composables/use-hs-multi-lang";
25
- // import { useHsMisc } from "../../composables/use-hs-misc";
26
- import { useHsIsMobile } from "../../composables/use-hs-is-mobile";
27
-
28
- // [ Components ]
29
- import InputFrame from "./input-frame.vue";
30
- import SelectImgIcon from "./select-img-icon.vue";
31
- import Btn from "../form/btn.vue";
32
-
33
- // ----------------------------------------------------------------------------
34
- const hsFocus = useHsFocus();
35
- const multiLang = useHsMultiLang();
36
- const tx = multiLang.tx;
37
- const gt = multiLang.gt;
38
- // const hsMisc = useHsMisc();
39
-
40
- // ----------------------------------------------------------------------------
41
- // [ Props ]
42
- type Props = {
43
- // ----------------------------------------------------------------------------
44
- // Input 種類別
45
- list: SelectItem<IdType>[];
46
- order?: boolean;
47
- loading?: boolean;
48
- nullText?: MultiLang;
49
- image?: boolean;
50
- classImg?: ClassType;
51
- classImgTag?: ClassType;
52
- nullable?: boolean;
53
- searchable?: boolean;
54
- // ----------------------------------------------------------------------------
55
- data: IdType | null;
56
- diff?: IdType | null | undefined;
57
- tabindex?: string | undefined;
58
- // ----------------------------------------------------------------------------
59
- class?: ClassType;
60
- classHeader?: ClassType;
61
- classInput?: ClassType;
62
- // ----------------------------------------------------------------------------
63
- // 状態
64
- // focus?: boolean;
65
- focusColor?: string;
66
- // change?: boolean;
67
- changeColor?: string;
68
- error?: boolean;
69
- errorColor?: string;
70
- disabled?: boolean;
71
- disabledColor?: string;
72
- readonly?: boolean;
73
- headerless?: boolean;
74
- // ----------------------------------------------------------------------------
75
- // 表示
76
- label?: MultiLang;
77
- // 表示-副情報
78
- require?: boolean;
79
- requireText?: MultiLang;
80
- warn?: string;
81
- warnTimeOut?: number;
82
- // ----------------------------------------------------------------------------
83
- // 設定
84
- size?: "s" | "m" | "l";
85
- };
86
-
87
- const props = withDefaults(defineProps<Props>(), {
88
- // ----------------------------------------------------------------------------
89
- // Input 種類別
90
- order: false,
91
- loading: false,
92
- nullText: () => ({ ja: "選択してください", en: "Select..." }),
93
- nullable: false,
94
- image: false,
95
- classImg: "",
96
- classImgTag: "",
97
- // ----------------------------------------------------------------------------
98
- diff: undefined,
99
- tabindex: undefined,
100
- // ----------------------------------------------------------------------------
101
- class: "",
102
- classHeader: "",
103
- classInput: "",
104
- // ----------------------------------------------------------------------------
105
- // 状態
106
- // focus: false,
107
- focusColor: "shadow-[inset_0px_0px_1px_2px_#0d8ee4]",
108
- // change: false,
109
- changeColor: "shadow-[inset_0px_0px_1px_2px_#fd9831be]",
110
- error: false,
111
- errorColor: "shadow-[inset_0px_0px_1px_2px_#d80000dc]",
112
- disabled: false,
113
- disabledColor: "",
114
- readonly: false,
115
- headerless: false,
116
- // ----------------------------------------------------------------------------
117
- // 表示
118
- label: "",
119
- // 表示-副情報
120
- require: false,
121
- requireText: () => ({ ja: "必須", en: "Required" }),
122
- warn: "",
123
- warnTimeOut: 3000,
124
- // ----------------------------------------------------------------------------
125
- // 設定
126
- size: "m",
127
- });
128
- // ----------------------------------------------------------------------------
129
- type EmitIdType = IdType extends string ? string : number;
130
-
131
- // [ emit ]
132
- type Emits = {
133
- ref: [element: HTMLElement];
134
- focus: [elm: HTMLElement];
135
- blur: [elm: HTMLElement];
136
- // ----------------------------
137
- "update:data": [value: EmitIdType | null];
138
- "value-change": [after: EmitIdType | null, before: EmitIdType | null];
139
- // ----------------------------
140
- keydown: [event: KeyboardEvent];
141
- keyup: [event: KeyboardEvent];
142
- selectOpen: [uid: string];
143
- selectClose: [uid: string];
144
- // ----------------------------
145
- };
146
- const emit = defineEmits<Emits>();
147
- // ----------------------------------------------------------------------------
148
- const slots = defineSlots<{
149
- default(props: { msg: string }): any;
150
- overlay?(): any;
151
- "right-icons"?(): any;
152
- "left-icons"?(): any;
153
- }>();
154
- // ----------------------------------------------------------------------------
155
- // [ getCurrentInstance ]
156
- const uid = useId();
157
- // ----------------------------------------------------------------------------
158
- // 更新の有無判定
159
- const isChangeData = computed(() => {
160
- if (props.diff === undefined) return false;
161
- if (props.diff !== props.data) return true;
162
- return false;
163
- });
164
- // [ ref ]
165
-
166
- // ----------------------------------------------------------------------------
167
- const displayData = ref<DisplaySelectItem<IdType> | null>(null);
168
- watch(displayData, (v) => {
169
- const before = props.data;
170
- if (v === null) {
171
- if (before === null) return;
172
- emit("update:data", null);
173
- emit("value-change", null, before as any as EmitIdType | null);
174
- return;
175
- }
176
- if (v.id === null) {
177
- displayData.value = null;
178
- return;
179
- }
180
- if (v.id === before) return;
181
- emit("update:data", v.id as any as EmitIdType | null);
182
- emit(
183
- "value-change",
184
- v.id as any as EmitIdType | null,
185
- before as any as EmitIdType | null
186
- );
187
- });
188
-
189
- // ----------------------------------------------------------------------------
190
- // 不明選択肢太陽
191
- const unKnownSelected = ref<boolean>(false);
192
- const unKnownData = computed(() => {
193
- if (props.data === null) return null;
194
- return {
195
- id: props.data,
196
- text: gt({
197
- ja: `無効な値が選択されています (ID=${props.data})`,
198
- en: `Invalid value selected (ID=${props.data})`,
199
- }),
200
- };
201
- });
202
-
203
- // ----------------------------------------------------------------------------
204
- const isShowHidden = ref(false);
205
- /** 選択肢に非表示アイテムが含まれているかどうか */
206
-
207
- const pList = computed(() => {
208
- return ObjectCopy(props.list);
209
- });
210
- const includeHidden = computed(() => {
211
- return pList.value.filter((row) => row.hidden).length > 0;
212
- });
213
- // ----------------------------------------------------------------------------
214
- /** 選択肢 */
215
- const displayList = ref<DisplaySelectItem<IdType>[]>([]);
216
- const baseList = computed(() => {
217
- return ObjectCopy(props.list).map((row) => {
218
- return { ...row, text: gt(row.text) };
219
- });
220
- });
221
-
222
- const setDisplayList = () => {
223
- displayList.value = useDisplayList<IdType>({
224
- list: baseList.value,
225
- id: props.data,
226
- order: props.order,
227
- unKnownData: unKnownData.value,
228
- unKnownSelected: unKnownSelected.value,
229
- isShowHidden: isShowHidden.value,
230
- require: props.require || !props.nullable,
231
- nullText: tx(props.nullText).value,
232
- });
233
- };
234
- watch(
235
- () => props.list,
236
- () => {
237
- nextTick(() => {
238
- setDisplayList();
239
- });
240
- },
241
- { deep: true }
242
- );
243
-
244
- watch(
245
- () => [
246
- props.list,
247
- props.list.length,
248
- props.data,
249
- isShowHidden.value,
250
- props.require,
251
- props.nullable,
252
- props.nullText,
253
- ],
254
- () => {
255
- nextTick(() => {
256
- setDisplayList();
257
- });
258
- },
259
- { immediate: true }
260
- );
261
-
262
- // ----------------------------------------------------------------------------
263
-
264
- const checkData = (id: IdType | null) => {
265
- // console.log("checkData");
266
- const ret = baseList.value.find((row) => row.id === id);
267
- if (ret === undefined) {
268
- // 選択肢に存在しないコード引当
269
- unKnownSelected.value = true;
270
- displayData.value = unKnownData.value;
271
- } else {
272
- unKnownSelected.value = false;
273
- displayData.value = ret;
274
- }
275
- };
276
- checkData(props.data);
277
- // const activateItem = computed(() => {
278
- watch(
279
- () => props.data,
280
- (id) => {
281
- checkData(id);
282
- }
283
- );
284
- watch(baseList, () => {
285
- // console.log("change list");
286
- nextTick(() => {
287
- checkData(props.data);
288
- });
289
- });
290
- // ----------------------------------------------------------------------------
291
-
292
- // [ focus, blur ]
293
- interface FocusState {
294
- isActivate: boolean;
295
- isOpen: boolean;
296
- }
297
- const focusState = reactive<FocusState>({
298
- isActivate: false,
299
- isOpen: false,
300
- });
301
-
302
- /**
303
- * コントロールのFocus判定
304
- */
305
- const computedActivate = computed(() => {
306
- if (props.disabled === true) return false;
307
- if (props.readonly === true) return false;
308
- if (focusState.isActivate) return true;
309
- if (focusState.isOpen) return true;
310
- if (hsFocus.state.id !== uid) return false;
311
- return false;
312
- });
313
-
314
- // ----------------------------------------------------------------------------
315
- // const isOpen = ref(false);
316
- const onFocus = () => {
317
- // console.log('onFocus');
318
- if (props.disabled === true) return;
319
- if (props.readonly === true) return;
320
- focusState.isActivate = true;
321
- hsFocus.state.id = uid;
322
- };
323
- const onBlur = () => {
324
- // console.log('onBlur');
325
- focusState.isActivate = false;
326
- };
327
- const selectOpen = () => {
328
- emit("selectOpen", uid);
329
- focusState.isOpen = true;
330
- };
331
- const selectClose = () => {
332
- // console.log('selectClose');
333
- focusState.isOpen = false;
334
- emit("selectClose", uid);
335
- };
336
- // const placement = ref("top");
337
- const inputElement = ref<HTMLElement | null>(null);
338
- // const withPopper = (dropdownList: any, component: any, { width }: any) => {
339
- // dropdownList.style.width = width;
340
- // const popper = createPopper(component.$refs.toggle, dropdownList, {
341
- // placement: placement.value as any,
342
- // modifiers: [
343
- // {
344
- // name: "offset",
345
- // options: {
346
- // offset: [0, -1],
347
- // },
348
- // },
349
- // {
350
- // name: "toggleClass",
351
- // enabled: true,
352
- // phase: "write",
353
- // fn({ state }) {
354
- // component.$el.classList.toggle("drop-up", state.placement === "top");
355
- // },
356
- // },
357
- // ],
358
- // });
359
- // return () => popper.destroy();
360
- // };
361
- // :calculate-position="withPopper"
362
- const isMobile = useHsIsMobile();
363
- // ----------------------------------------------------------------------------
364
- // ----------------------------------------------------------------------------
365
- </script>
366
-
367
- <template>
368
- <InputFrame
369
- :class="[props.class]"
370
- :class-header="props.classHeader"
371
- :class-input="['px-0', props.classInput]"
372
- :focus="computedActivate"
373
- :focus-color="props.focusColor"
374
- :change="isChangeData"
375
- :change-color="props.changeColor"
376
- :error="props.error"
377
- :error-color="props.errorColor"
378
- :disabled="props.disabled"
379
- :disabled-color="props.disabledColor"
380
- :readonly="props.readonly"
381
- :label="props.label"
382
- :require="props.require"
383
- :require-text="tx(props.requireText).value"
384
- :warn="props.warn"
385
- :warn-time-out="props.warnTimeOut"
386
- :size="props.size"
387
- :headerless="props.headerless"
388
- >
389
- <template v-if="slots['left-icons']" #left-icons>
390
- <slot name="left-icons" :disabled="disabled" />
391
- </template>
392
- <template v-if="slots['right-icons']" #right-icons>
393
- <slot name="right-icons" :disabled="disabled" />
394
- </template>
395
- <template v-if="slots.overlay" #overlay>
396
- <slot name="overlay"></slot>
397
- </template>
398
- <div
399
- v-if="displayData === null"
400
- class="absolute inset-0 flex items-center px-1 pointer-events-none text-[0.9em]"
401
- :class="[computedActivate ? 'opacity-30' : '']"
402
- >
403
- {{ tx(props.nullText) }}
404
- </div>
405
- <v-select
406
- ref="inputElement"
407
- v-model="displayData"
408
- label="text"
409
- index="id"
410
- append-to-body
411
- :options="displayList"
412
- :loading="props.loading"
413
- :searchable="!isMobile.isMobile && searchable"
414
- :clearable="!props.require && props.nullable"
415
- :disabled="props.disabled || props.readonly"
416
- :uid="uid"
417
- :class="[
418
- `size-${props.size}`,
419
- { disabled: props.disabled || props.readonly },
420
- ]"
421
- @open="selectOpen"
422
- @close="selectClose"
423
- @blur="onBlur()"
424
- @focus="onFocus()"
425
- >
426
- <!-- :autoscroll="false" -->
427
- <!-- -->
428
- <!-- -->
429
- <!-- -->
430
- <template #selected-option="{ text, imgUrl, deleted, appendIcon }">
431
- <div
432
- class="flex items-baseline w-full max-w-full min-w-0"
433
- :class="loading ? 'opacity-0' : ''"
434
- >
435
- <SelectImgIcon
436
- v-if="imgUrl && props.image"
437
- class="flex-none"
438
- :class="[computedActivate ? 'opacity-40' : '']"
439
- :img-url="imgUrl"
440
- :class-img="props.classImg"
441
- :class-img-tag="props.classImgTag"
442
- />
443
- <div class="flex-1 truncate min-w-0">{{ text }}</div>
444
- <div v-if="deleted" class="text-error text-[0.7em] leading-[1em]">
445
- {{ tx({ ja: "削除済", en: "Deleted" }) }}
446
- </div>
447
- <!-- <div v-if="hidden" class="text-error text-[0.7em] leading-[1em]">
448
- {{ tx({ ja: "非表示", en: "Hidden" }) }}
449
- </div> -->
450
- <div
451
- v-if="appendIcon && typeof appendIcon === 'string'"
452
- class="flex-none"
453
- >
454
- <i :class="appendIcon"></i>
455
- </div>
456
-
457
- <div
458
- v-else-if="appendIcon && Array.isArray(appendIcon)"
459
- class="flex-none"
460
- >
461
- <i v-for="(c, i) in appendIcon" :key="i" :class="c"></i>
462
- </div>
463
- </div>
464
- </template>
465
- <template #option="{ text, imgUrl, deleted, hidden, appendIcon }">
466
- <div class="flex items-center">
467
- <SelectImgIcon
468
- v-if="props.image"
469
- class="flex-none"
470
- :img-url="imgUrl"
471
- :class-img="props.classImg"
472
- :class-img-tag="props.classImgTag"
473
- />
474
- <div class="flex-1 truncate">{{ text }}</div>
475
- <div v-if="deleted" class="text-error text-[0.7em] leading-[1em]">
476
- {{ tx({ ja: "削除済", en: "Deleted" }) }}
477
- </div>
478
- <div v-if="hidden" class="text-error text-[0.7em] leading-[1em]">
479
- {{ tx({ ja: "非表示", en: "Hidden" }) }}
480
- </div>
481
- <span v-if="appendIcon && typeof appendIcon === 'string'">
482
- <i :class="appendIcon"></i>
483
- </span>
484
- <span v-else-if="appendIcon && Array.isArray(appendIcon)">
485
- <i v-for="(c, i) in appendIcon" :key="i" :class="c"></i>
486
- </span>
487
- </div>
488
- </template>
489
- <template v-if="includeHidden" #list-footer>
490
- <li class="vs__dropdown-option v-select-hidden-toggle-switch">
491
- <Btn
492
- theme="accent1"
493
- variant="outlined"
494
- class="w-full"
495
- size="xs"
496
- @click="isShowHidden = !isShowHidden"
497
- >
498
- <span class="me-1">Hidden options</span>
499
- <i
500
- class="fas"
501
- :class="[
502
- !isShowHidden
503
- ? 'fa-eye-slash text-error'
504
- : 'fa-eye text-success',
505
- ]"
506
- ></i>
507
- <i class="fas fa-caret-right mx-1"></i>
508
- <i
509
- class="fas"
510
- :class="[
511
- isShowHidden
512
- ? 'fa-eye-slash text-error'
513
- : 'fa-eye text-success',
514
- ]"
515
- ></i>
516
- </Btn>
517
- </li>
518
- </template>
519
- </v-select>
520
- </InputFrame>
521
- </template>
522
-
1
+ <script setup>
2
+ import {
3
+ reactive,
4
+ ref,
5
+ watch,
6
+ computed,
7
+ useId,
8
+ defineShortcuts,
9
+ nextTick,
10
+ onMounted,
11
+ useTemplateRef
12
+ } from "#imports";
13
+ import { ObjectCopy } from "../../utils/object";
14
+ import { InitModalControl, InitModals } from "../../utils/modal";
15
+ import { useHsFocus } from "../../composables/use-hs-focus";
16
+ import { useHsPinia } from "../../composables/use-pinia";
17
+ import { useHsMultiLang } from "../../composables/use-hs-multi-lang";
18
+ import { useHsScrollLock } from "../../composables/use-hs-scroll-lock";
19
+ import { useHsMisc } from "../../composables/use-hs-misc";
20
+ import InputFrame from "./input-frame.vue";
21
+ import Btn from "../form/btn.vue";
22
+ import SelectHiddenItemToggle from "./_select/hidden-item-toggle.vue";
23
+ import { useHsIsMobile } from "../../composables/use-hs-is-mobile";
24
+ import TextBox from "../form/text-box.vue";
25
+ import SelectItemContainer from "./_select/item-container.vue";
26
+ import ViewSelectItemRow from "./_select/item-row.vue";
27
+ const props = defineProps({
28
+ list: { type: Array, required: true },
29
+ order: { type: Boolean, required: false, default: false },
30
+ loading: { type: Boolean, required: false, default: false },
31
+ nullText: { type: [String, Object], required: false, default: () => ({ ja: "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044", en: "Select..." }) },
32
+ unknownText: { type: [String, Object], required: false, default: () => ({
33
+ ja: "\u7121\u52B9\u306A\u9078\u629E\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059",
34
+ en: "An invalid selection has been made"
35
+ }) },
36
+ img: { type: Boolean, required: false },
37
+ imgMode: { type: String, required: false, default: "contain" },
38
+ classImg: { type: [String, Object, Array], required: false, default: "" },
39
+ classImgTag: { type: [String, Object, Array], required: false, default: "" },
40
+ nullable: { type: Boolean, required: false, default: false },
41
+ searchable: { type: Boolean, required: false },
42
+ class: { type: [String, Object, Array], required: false, default: "" },
43
+ classHeader: { type: [String, Object, Array], required: false, default: "" },
44
+ classInput: { type: [String, Object, Array], required: false, default: "" },
45
+ data: { type: null, required: true },
46
+ diff: { type: null, required: false, default: void 0 },
47
+ tabindex: { type: null, required: false, default: void 0 },
48
+ focusColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#0d8ee4]" },
49
+ changeColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#fd9831be]" },
50
+ error: { type: Boolean, required: false, default: false },
51
+ errorColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#d80000dc]" },
52
+ disabled: { type: Boolean, required: false, default: false },
53
+ disabledColor: { type: String, required: false, default: "" },
54
+ readonly: { type: Boolean, required: false, default: false },
55
+ headerless: { type: Boolean, required: false, default: false },
56
+ label: { type: [String, Object], required: false, default: "" },
57
+ require: { type: Boolean, required: false, default: false },
58
+ requireText: { type: [String, Object], required: false, default: () => ({ ja: "\u5FC5\u9808", en: "Required" }) },
59
+ warn: { type: String, required: false, default: "" },
60
+ warnTimeOut: { type: Number, required: false, default: 3e3 },
61
+ size: { type: String, required: false, default: "m" }
62
+ });
63
+ const emit = defineEmits(["update:data", "value-change", "focus", "blur"]);
64
+ const slots = defineSlots();
65
+ const multiLang = useHsMultiLang(useHsPinia());
66
+ const tx = multiLang.tx;
67
+ const gt = multiLang.gt;
68
+ const hsFocus = useHsFocus(useHsPinia());
69
+ const hsIsMobile = useHsIsMobile(useHsPinia());
70
+ const hsMisc = useHsMisc(useHsPinia());
71
+ onMounted(() => {
72
+ hsIsMobile.init();
73
+ });
74
+ const uid = useId();
75
+ const inputFrameElm = ref();
76
+ const searchWord = ref("");
77
+ const selectOpen = ref(false);
78
+ const openToggle = () => {
79
+ if (selectOpen.value || modal.sp.isShow) {
80
+ selectOpen.value = false;
81
+ modal.sp.close();
82
+ return;
83
+ }
84
+ if (props.disabled) return;
85
+ if (props.readonly) return;
86
+ if (props.searchable && hsIsMobile.isMobile) {
87
+ modal.sp.show();
88
+ } else {
89
+ selectOpen.value = true;
90
+ }
91
+ };
92
+ const lock = computed(() => {
93
+ return props.disabled || props.readonly;
94
+ });
95
+ const activeValue = ref(props.data);
96
+ watch(
97
+ () => props.data,
98
+ () => {
99
+ activeValue.value = props.data;
100
+ }
101
+ );
102
+ let versionCounter = 0;
103
+ const nullItem = computed(() => {
104
+ return { id: null, text: props.nullText };
105
+ });
106
+ const listBase = computed(() => {
107
+ versionCounter++;
108
+ const ret = ObjectCopy(
109
+ props.list.map((row) => {
110
+ return {
111
+ ...row,
112
+ text: gt(row.text) || "",
113
+ _key: `${row.id}:${versionCounter ?? 0}`
114
+ };
115
+ })
116
+ );
117
+ if (props.nullable) {
118
+ ret.unshift(nullItem.value);
119
+ }
120
+ return ret;
121
+ });
122
+ const hasLabel = computed(() => {
123
+ return !!props.list.find((row) => !!row.groupId);
124
+ });
125
+ const activeRow = computed(() => {
126
+ return listBase.value.find((row) => row.id === activeValue.value) || null;
127
+ });
128
+ const diffDisplayText = computed(() => {
129
+ if (!props.diff) return "";
130
+ const data = listBase.value.find((row) => row.id === props.diff) || null;
131
+ if (!data) return props.nullText;
132
+ return tx(data.text).value;
133
+ });
134
+ const hiddenItemVisible = ref(false);
135
+ const hasHiddenItem = computed(() => {
136
+ return props.list.filter((row) => {
137
+ if (row.deleted) return false;
138
+ if (row.hidden) return true;
139
+ return false;
140
+ }).length !== 0;
141
+ });
142
+ const updateData = (value) => {
143
+ if (props.disabled === true) return false;
144
+ if (props.readonly === true) return false;
145
+ const before = props.data;
146
+ if (!value) {
147
+ if (!props.nullable) return;
148
+ emit("update:data", value);
149
+ emit("value-change", value, before);
150
+ return;
151
+ }
152
+ emit("update:data", value);
153
+ emit("value-change", value, before);
154
+ };
155
+ const displayList = computed(() => {
156
+ const ret = listBase.value.filter((row) => {
157
+ if (row.id === props.data) return true;
158
+ if (row.deleted) return false;
159
+ if (!hiddenItemVisible.value && row.hidden) {
160
+ return false;
161
+ }
162
+ return true;
163
+ }).sort((a, b) => {
164
+ if (a.order === void 0 || b.order === void 0) return 0;
165
+ if (a.order < b.order) return -1;
166
+ if (a.order > b.order) return 1;
167
+ return 0;
168
+ });
169
+ return ret;
170
+ });
171
+ const isChangeData = computed(() => {
172
+ if (props.diff === void 0) return false;
173
+ if (props.diff !== props.data) return true;
174
+ return false;
175
+ });
176
+ const focusState = reactive({
177
+ isActivate: false,
178
+ openActual: false
179
+ });
180
+ const onFocus = () => {
181
+ if (props.disabled === true) return;
182
+ if (props.readonly === true) return;
183
+ focusState.isActivate = true;
184
+ if (hsFocus.state.id !== uid) {
185
+ hsFocus.state.id = uid;
186
+ }
187
+ };
188
+ const onBlur = () => {
189
+ focusState.isActivate = false;
190
+ };
191
+ const focusId = computed(() => hsFocus.state.id);
192
+ watch(focusId, () => {
193
+ if (hsFocus.state.id !== uid) {
194
+ focusState.openActual = false;
195
+ selectOpen.value = false;
196
+ }
197
+ });
198
+ watch(selectOpen, (v) => {
199
+ if (!v) {
200
+ setTimeout(() => {
201
+ focusState.openActual = false;
202
+ }, 300);
203
+ } else {
204
+ focusState.openActual = true;
205
+ if (hsFocus.state.id !== uid) {
206
+ hsFocus.state.id = uid;
207
+ }
208
+ }
209
+ });
210
+ defineShortcuts({
211
+ delete: {
212
+ // 入力フォーカス中でも発火させたいなら true(環境によっては省略でOK)
213
+ usingInput: false,
214
+ handler: (e) => {
215
+ if (selectOpen.value) return;
216
+ if (!focusState.isActivate) return;
217
+ e.preventDefault();
218
+ updateData(null);
219
+ }
220
+ },
221
+ backspace: {
222
+ usingInput: false,
223
+ handler: (e) => {
224
+ if (selectOpen.value) return;
225
+ if (!focusState.isActivate) return;
226
+ e.preventDefault();
227
+ updateData(null);
228
+ }
229
+ },
230
+ enter: {
231
+ usingInput: false,
232
+ handler: () => {
233
+ if (selectOpen.value) return;
234
+ if (!focusState.isActivate) return;
235
+ selectOpen.value = !selectOpen.value;
236
+ }
237
+ }
238
+ });
239
+ const content = {
240
+ disableOutsidePointerEvents: true,
241
+ bodyLock: false
242
+ };
243
+ const uiBase = [
244
+ "bg-transparent",
245
+ "max-w-full text-left",
246
+ "focus-visible:outline-none focus:outline-none ring-0 focus:ring-0",
247
+ "py-0 pr-[10px]",
248
+ "focus-visible:ring-0 "
249
+ ];
250
+ const modal = reactive({
251
+ sp: InitModalControl()
252
+ });
253
+ onMounted(() => InitModals(modal, nextTick));
254
+ const modalSpScrollTop = () => {
255
+ if (!modalSpScrollTopTarget.value) return;
256
+ modalSpScrollTopTarget.value?.scrollIntoView();
257
+ };
258
+ modal.sp.showBefore = async () => {
259
+ if (!activeValue.value) return modalSpScrollTop();
260
+ const target = spFilterList.value.find((row) => row.id === activeValue.value);
261
+ if (target === void 0 || !target.html) return modalSpScrollTop();
262
+ target.html.scrollIntoView();
263
+ };
264
+ const modalSpScrollTopTarget = useTemplateRef("modalSpScrollTopTarget");
265
+ const scrollLock = useHsScrollLock();
266
+ const modalElm = useTemplateRef("modalElm");
267
+ watch(modalElm, (elm) => {
268
+ if (elm !== null) scrollLock.init(elm);
269
+ });
270
+ watch(
271
+ () => modal.sp.isShow,
272
+ (v) => {
273
+ if (v) {
274
+ scrollLock.lock();
275
+ } else {
276
+ scrollLock.unlock();
277
+ }
278
+ }
279
+ );
280
+ const showSpModal = () => {
281
+ if (props.disabled) return;
282
+ if (props.readonly) return;
283
+ modal.sp.show();
284
+ };
285
+ const norm = (s) => {
286
+ return s.normalize("NFKC");
287
+ };
288
+ const spFilterList = computed(() => {
289
+ return displayList.value.filter((row) => {
290
+ if (!searchWord.value) return true;
291
+ if (norm(row.text).toLocaleLowerCase().includes(norm(searchWord.value).toLocaleLowerCase())) {
292
+ return true;
293
+ }
294
+ return false;
295
+ }).map((row) => {
296
+ return {
297
+ ...row,
298
+ html: null
299
+ };
300
+ });
301
+ });
302
+ const computedActivate = computed(() => {
303
+ if (props.disabled === true) return false;
304
+ if (props.readonly === true) return false;
305
+ if (selectOpen.value) return true;
306
+ if (modal.sp.isShow) return true;
307
+ if (hsFocus.state.id !== uid) return false;
308
+ if (focusState.openActual) return true;
309
+ if (focusState.isActivate) return true;
310
+ return false;
311
+ });
312
+ watch(computedActivate, (value) => {
313
+ if (value === true) {
314
+ setTimeout(() => {
315
+ emit("focus");
316
+ }, 10);
317
+ } else {
318
+ emit("blur");
319
+ }
320
+ });
321
+ </script>
322
+
323
+ <template>
324
+ <InputFrame
325
+ :class="['HsSelect', props.class]"
326
+ :class-header="props.classHeader"
327
+ :class-input="[' px-0 flex items-center flex-1', props.classInput]"
328
+ :focus="computedActivate"
329
+ :focus-color="props.focusColor"
330
+ :change="isChangeData"
331
+ :change-color="props.changeColor"
332
+ :error="props.error"
333
+ :error-color="props.errorColor"
334
+ :disabled="props.disabled"
335
+ :disabled-color="props.disabledColor"
336
+ :readonly="props.readonly"
337
+ :label="props.label"
338
+ :require="props.require"
339
+ :require-text="tx(props.requireText).value"
340
+ :warn="props.warn"
341
+ :warn-time-out="props.warnTimeOut"
342
+ :size="props.size"
343
+ :headerless="props.headerless"
344
+ @focusin="onFocus"
345
+ @focusout="onBlur"
346
+ @ref="(e) => inputFrameElm = e"
347
+ @click="openToggle()"
348
+ >
349
+ <template #overlay="{ focus, change }">
350
+ <div
351
+ v-if="props.diff !== void 0 && change"
352
+ class="absolute inset-0 bg-red/30 transition-opacity flex items-center p-1 bg-dark/20"
353
+ :class="!focus && hsMisc.capsLockState ? 'opacity-100' : 'opacity-0 pointer-events-none select-none'"
354
+ >
355
+ <div class="flex" @mousedown.prevent @click.prevent>
356
+ <Btn
357
+ variant="outlined"
358
+ theme="error"
359
+ tabindex="-1"
360
+ size="xs"
361
+ class="bg-white flex-none"
362
+ @click.stop="updateData(props.diff)"
363
+ >
364
+ <i class="fa-solid fa-rotate-right"></i>
365
+ </Btn>
366
+ <div v-if="props.diff" class="px-1 truncate bg-white mx-1 flex items-center select-none" @click.stop>
367
+ {{ diffDisplayText }}
368
+ </div>
369
+ </div>
370
+ </div>
371
+ <template v-if="slots.overlay">
372
+ <slot name="overlay" :focus="focus" :change="change"></slot>
373
+ </template>
374
+ </template>
375
+ <template v-if="slots['left-icons']" #left-icons>
376
+ <slot name="left-icons" :disabled="disabled" />
377
+ </template>
378
+ <template #right-icons>
379
+ <Btn
380
+ v-if="!lock && props.nullable && props.data !== null"
381
+ variant="text"
382
+ theme="error"
383
+ tabindex="-1"
384
+ class="text-error w-[1.4em] hover:bg-accent1/10 mr-1"
385
+ @click.stop="updateData(null)"
386
+ >
387
+ <i class="fa-solid fa-xmark"></i>
388
+ </Btn>
389
+ <Btn
390
+ v-if="!lock"
391
+ variant="text"
392
+ theme="accent1"
393
+ tabindex="-1"
394
+ class="text-accent1 w-[1.4em] hover:bg-accent1/10 mr-1"
395
+ @click.stop="openToggle()"
396
+ >
397
+ <i class="fa-solid fa-chevron-down transition-all" :class="[selectOpen ? 'rotate-x-180' : '']"></i>
398
+ </Btn>
399
+ <slot name="right-icons" :disabled="disabled" />
400
+ </template>
401
+ <template v-if="slots['label-prepend']" #label-prepend>
402
+ <slot name="label-prepend" />
403
+ </template>
404
+ <template v-if="slots['label-append']" #label-append>
405
+ <slot name="label-append" />
406
+ </template>
407
+ <template v-if="slots['header-right']" #header-right>
408
+ <slot name="header-right" />
409
+ </template>
410
+ <template #default>
411
+ <template v-if="!props.searchable">
412
+ <USelect
413
+ v-model:open="selectOpen"
414
+ :model-value="activeValue"
415
+ :items="displayList"
416
+ value-key="id"
417
+ label-key="text"
418
+ class="w-full"
419
+ :trailing="false"
420
+ trailing-icon=""
421
+ :ui="{
422
+ base: uiBase,
423
+ item: ['!bg-white focus:bg-white active:bg-white p-0']
424
+ }"
425
+ :content="{
426
+ reference: inputFrameElm,
427
+ ...content
428
+ }"
429
+ :disabled="lock"
430
+ :close-on-select="false"
431
+ @update:model-value="(v) => updateData(v)"
432
+ >
433
+ <template #default>
434
+ <div
435
+ class="flex items-center w-full"
436
+ :class="[
437
+ props.disabled ? 'cursor-not-allowed' : '',
438
+ //
439
+ props.readonly ? 'cursor-text' : '',
440
+ //
441
+ !lock ? 'cursor-pointer' : ''
442
+ //
443
+ ]"
444
+ @click.stop="openToggle()"
445
+ >
446
+ <template v-if="activeRow">
447
+ <SelectItemContainer
448
+ :item="activeRow"
449
+ :value="activeValue"
450
+ :img="props.img"
451
+ :activated="props.img"
452
+ :class-img="props.classImg"
453
+ :class-img-tag="props.classImgTag"
454
+ :img-mode="props.imgMode"
455
+ :disabled="props.disabled"
456
+ :readonly="props.readonly"
457
+ type="display"
458
+ />
459
+ </template>
460
+ <template v-else-if="!!props.data">
461
+ <div class="min-w-0 truncate flex-1 text-[1rem]" :class="[!props.disabled ? 'text-error' : '']">
462
+ {{ tx(props.unknownText) }}
463
+ </div>
464
+ </template>
465
+ <template v-else>
466
+ <div class="min-w-0 truncate flex-1 text-[1rem]" :class="[!props.disabled ? 'text-gray-700' : '']">
467
+ {{ tx(props.nullText) }}
468
+ </div>
469
+ </template>
470
+ </div>
471
+ </template>
472
+ <template #trailing>
473
+ <div></div>
474
+ </template>
475
+ <template #item="{ item, index }">
476
+ <ViewSelectItemRow
477
+ :list="displayList"
478
+ :item="item"
479
+ :index="index"
480
+ :active-id="activeValue"
481
+ :has-label="hasLabel"
482
+ :img="props.img"
483
+ :class-img="props.classImg"
484
+ :class-img-tag="props.classImgTag"
485
+ :img-mode="props.imgMode"
486
+ :disabled="props.disabled"
487
+ :readonly="props.readonly"
488
+ />
489
+ </template>
490
+ <template v-if="hasHiddenItem" #content-bottom>
491
+ <div class="p-1">
492
+ <SelectHiddenItemToggle v-model:hidden-item-visible="hiddenItemVisible" />
493
+ </div>
494
+ </template>
495
+ </USelect>
496
+ </template>
497
+ <template v-else-if="props.searchable && !hsIsMobile.isMobile">
498
+ <USelectMenu
499
+ v-model:serach-term="searchWord"
500
+ v-model:open="selectOpen"
501
+ :model-value="activeValue"
502
+ :items="displayList"
503
+ value-key="id"
504
+ label-key="text"
505
+ class="w-full"
506
+ :trailing="false"
507
+ trailing-icon=""
508
+ :ui="{
509
+ base: uiBase,
510
+ item: ['!bg-white focus:bg-white active:bg-white p-0']
511
+ }"
512
+ :content="{
513
+ reference: inputFrameElm,
514
+ ...content
515
+ }"
516
+ :disabled="lock"
517
+ :close-on-select="false"
518
+ @update:model-value="(v) => updateData(v)"
519
+ >
520
+ <template #default>
521
+ <div
522
+ :key="activeRow?._key || 'null-_base'"
523
+ class="flex items-center w-full"
524
+ :class="[
525
+ props.disabled ? 'cursor-not-allowed' : '',
526
+ //
527
+ props.readonly ? 'cursor-text' : '',
528
+ //
529
+ !lock ? 'cursor-pointer' : ''
530
+ //
531
+ ]"
532
+ @click.stop="openToggle()"
533
+ >
534
+ <template v-if="activeRow">
535
+ <SelectItemContainer
536
+ :item="activeRow"
537
+ :value="activeValue"
538
+ :img="props.img"
539
+ :activated="props.img"
540
+ :class-img="props.classImg"
541
+ :class-img-tag="props.classImgTag"
542
+ :img-mode="props.imgMode"
543
+ :disabled="props.disabled"
544
+ :readonly="props.readonly"
545
+ type="display"
546
+ />
547
+ </template>
548
+ <template v-else-if="!!props.data">
549
+ <div class="min-w-0 truncate flex-1 text-[1rem]" :class="[!props.disabled ? 'text-error' : '']">
550
+ {{ tx(props.unknownText) }}
551
+ </div>
552
+ </template>
553
+ <template v-else>
554
+ <div class="min-w-0 truncate flex-1" :class="[!props.disabled ? 'text-gray-700' : '']">
555
+ {{ tx(props.nullText) }}
556
+ </div>
557
+ </template>
558
+ </div>
559
+ </template>
560
+ <template #trailing>
561
+ <div></div>
562
+ </template>
563
+ <template #item="{ item, index }">
564
+ <ViewSelectItemRow
565
+ :key="item.id"
566
+ :list="displayList"
567
+ :item="item"
568
+ :index="index"
569
+ :active-id="activeValue"
570
+ :has-label="hasLabel"
571
+ :img="props.img"
572
+ :class-img="props.classImg"
573
+ :class-img-tag="props.classImgTag"
574
+ :img-mode="props.imgMode"
575
+ :disabled="props.disabled"
576
+ :readonly="props.readonly"
577
+ />
578
+ </template>
579
+ <template v-if="hasHiddenItem" #content-bottom>
580
+ <div class="p-1">
581
+ <SelectHiddenItemToggle v-model:hidden-item-visible="hiddenItemVisible" />
582
+ </div>
583
+ </template>
584
+ </USelectMenu>
585
+ </template>
586
+ <template v-else>
587
+ <div
588
+ :key="activeRow?._key || 'null-_base'"
589
+ class="flex items-center w-full px-2.5 text-neutral-900"
590
+ :class="[
591
+ props.disabled ? 'cursor-not-allowed' : '',
592
+ //
593
+ props.readonly ? 'cursor-text' : '',
594
+ //
595
+ !lock ? 'cursor-pointer' : ''
596
+ //
597
+ ]"
598
+ @click.stop="showSpModal()"
599
+ >
600
+ <template v-if="activeRow">
601
+ <SelectItemContainer
602
+ :item="activeRow"
603
+ :value="activeValue"
604
+ :img="props.img"
605
+ :activated="props.img"
606
+ :class-img="props.classImg"
607
+ :class-img-tag="props.classImgTag"
608
+ :img-mode="props.imgMode"
609
+ :disabled="props.disabled"
610
+ :readonly="props.readonly"
611
+ type="display"
612
+ />
613
+ </template>
614
+ <template v-else-if="!!props.data">
615
+ <div class="min-w-0 truncate flex-1 text-[1rem]" :class="[!props.disabled ? 'text-error' : '']">
616
+ {{ tx(props.unknownText) }}
617
+ </div>
618
+ </template>
619
+ <template v-else>
620
+ <div class="min-w-0 truncate flex-1" :class="[!props.disabled ? 'text-gray-700' : '']">
621
+ {{ tx(props.nullText) }}
622
+ </div>
623
+ </template>
624
+ </div>
625
+ <Modal
626
+ :show="modal.sp.isShow"
627
+ closeable
628
+ @close="modal.sp.close();
629
+ selectOpen = false"
630
+ >
631
+ <Card ref="modalElm" class="HsSelectModal w-full max-w-125 max-h-full">
632
+ <CardItem variant="header" size="s" cross @update:open="modal.sp.close()">
633
+ <div>
634
+ {{ tx(props.label || { ja: "\u9078\u629E", en: "Please Select" }) }}
635
+ </div>
636
+ </CardItem>
637
+ <CardItem variant="body">
638
+ <div class="text-[14px] text-gray-600 leading-[1em] mb-1">{{ tx({ ja: "\u691C\u7D22", en: "Search" }) }}</div>
639
+ <TextBox v-model:data="searchWord" size="m" />
640
+ </CardItem>
641
+ <CardItem variant="body">
642
+ <div class="h-px w-full bg-main0/50"></div>
643
+ </CardItem>
644
+ <CardItem variant="body" scroll>
645
+ <div ref="modalSpScrollTopTarget" class="grid gap-1">
646
+ <template v-for="(row, index) in spFilterList" :key="index">
647
+ <div
648
+ v-if="
649
+ row.groupId !== void 0 && (index === 0 || spFilterList[index - 1]?.groupId !== row.groupId)
650
+ "
651
+ class="mt-1 py-1 px-2 font-semibold bg-dark/5 border-dark/40 border"
652
+ :class="index !== 0 ? 'mt-2' : ''"
653
+ >
654
+ {{ tx(row.groupLabel ?? "") }}
655
+ </div>
656
+ <div
657
+ :ref="(e) => row.html = e"
658
+ class="cursor-pointerw-full text-neutral-900 border rounded bg-white overflow-hidden"
659
+ :class="[
660
+ row.id === activeValue ? 'border-accent1' : 'border-black/20',
661
+ row.id !== null && hasLabel ? 'ml-2' : ''
662
+ ]"
663
+ @click="updateData(row.id);
664
+ modal.sp.close()"
665
+ >
666
+ <div class="flex items-center active:bg-accent1/10 p-3">
667
+ <SelectItemContainer
668
+ :item="row"
669
+ :value="activeValue"
670
+ :img="props.img"
671
+ :activated="props.img"
672
+ :class-img="props.classImg"
673
+ :class-img-tag="props.classImgTag"
674
+ :img-mode="props.imgMode"
675
+ :disabled="props.disabled"
676
+ :readonly="props.readonly"
677
+ type="item"
678
+ />
679
+ </div>
680
+ </div>
681
+ </template>
682
+ <div
683
+ v-if="listBase.length !== 0 && spFilterList.length === 0"
684
+ class="text-error whitespace-pre-line text-center"
685
+ >
686
+ {{
687
+ tx({
688
+ ja: "\u691C\u7D22\u6761\u4EF6\u306B\u4E00\u81F4\u3059\u308B\u7D50\u679C\u306F\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002\n\u4ED6\u306E\u30AD\u30FC\u30EF\u30FC\u30C9\u3067\u304A\u8A66\u3057\u304F\u3060\u3055\u3044\u3002",
689
+ en: "No results matched your search. \nPlease try different keywords."
690
+ })
691
+ }}
692
+ </div>
693
+ <div v-else-if="listBase.length === 0" class="text-error text-center">
694
+ {{
695
+ tx({
696
+ ja: "\u5229\u7528\u53EF\u80FD\u306A\u9078\u629E\u80A2\u304C\u3042\u308A\u307E\u305B\u3093",
697
+ en: "No selectable options"
698
+ })
699
+ }}
700
+ </div>
701
+ </div>
702
+ </CardItem>
703
+ <CardItem variant="body" class="pt-1 bg-back">
704
+ <SelectHiddenItemToggle v-if="hasHiddenItem" v-model:hidden-item-visible="hiddenItemVisible" />
705
+ </CardItem>
706
+ </Card>
707
+ </Modal>
708
+ </template>
709
+ </template>
710
+ </InputFrame>
711
+ </template>
712
+
523
713
  <style>
524
- .v-select > div {
525
- border-width: 0 !important;
526
- }
527
- .v-select:not(.vs--open).vs--single.vs--searchable .vs__selected {
528
- width: 100%;
529
- }
530
- .v-select.vs--open.vs--single.vs--searchable .vs__selected {
531
- width: calc(100% - 0.5em);
532
- }
533
- .v-select .vs__selected {
534
- margin-top: 0 !important;
535
- margin-bottom: 0 !important;
536
- flex: 1 1 auto;
537
- }
538
- .v-select .vs__selected,
539
- .v-select .vs__selected-options {
540
- max-width: 100%;
714
+ .HsSelect .icons > * {
715
+ height: auto;
716
+ height: calc(100% - 6px);
717
+ max-height: calc(100% - 6px);
718
+ min-height: 0;
541
719
  min-width: 0;
542
720
  }
543
- .v-select .vs__search {
544
- margin: 0 !important;
545
- }
546
- .v-select .vs__clear {
547
- padding: 3px;
548
- border: solid 1px transparent;
549
- transition: border-color 300ms;
550
- border-radius: 3px;
551
- }
552
- .v-select .vs__clear:focus {
553
- box-shadow: inset 0px 0px 1px 2px #0d8ee4;
554
- }
555
- .v-select .vs__dropdown-toggle {
556
- background-color: transparent;
557
- }
558
- .v-select.size-s .vs__dropdown-toggle {
559
- padding-bottom: 0 !important;
560
- height: 24px !important;
561
- }
562
- .v-select.size-s .vs__spinner {
563
- width: 3.5em;
564
- height: 3.5em;
565
- }
566
- .v-select.size-m .vs__dropdown-toggle {
567
- padding-bottom: 0 !important;
568
- height: 26px !important;
721
+ .HsSelect .icons > *:after {
722
+ display: none;
569
723
  }
570
- .v-select.size-m .vs__spinner {
571
- width: 4em;
572
- height: 4em;
724
+
725
+ .HsSelectItem:not(.active):hover {
726
+ background-color: var(--color-bg);
573
727
  }
574
- .v-select.disabled .vs__search,
575
- .v-select.disabled .vs__dropdown-toggle,
576
- .v-select.disabled .vs__open-indicator {
577
- background-color: transparent !important;
728
+
729
+ [data-highlighted] .HsSelectItem:hover {
730
+ background-color: var(--color-bg);
578
731
  }
579
- .v-select.disabled .vs__clear {
580
- display: none;
732
+
733
+ [data-highlighted] .HsSelectItem:not(:hover) {
734
+ background-color: var(--color-bg);
581
735
  }
582
736
 
583
- .vs__dropdown-menu {
584
- max-height: 250px;
737
+ [data-reka-popper-content-wrapper] > [data-dismissable-layer] {
738
+ filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.58));
585
739
  }
586
740
 
587
- .v-select-hidden-toggle-switch {
588
- pointer-events: all !important;
741
+ [data-reka-popper-content-wrapper] > [data-dismissable-layer] > span > svg {
742
+ fill: white;
589
743
  }
590
- </style>
744
+ </style>