nuxt-hs-ui 2.12.7 → 4.0.0-beta.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 (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 +125 -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.js +2 -1
  90. package/dist/runtime/composables/use-hs-toast.d.ts +2 -2
  91. package/dist/runtime/composables/use-hs-toast.js +12 -4
  92. package/dist/runtime/composables/use-pinia.d.ts +1 -0
  93. package/dist/runtime/composables/use-pinia.js +2 -0
  94. package/dist/runtime/plugin.d.ts +2 -0
  95. package/dist/runtime/plugin.js +4 -0
  96. package/dist/runtime/server/tsconfig.json +3 -3
  97. package/dist/runtime/types/dialog.d.ts +11 -20
  98. package/dist/runtime/types/dialog.js +2 -1
  99. package/dist/runtime/types/flatpickr/default.js +2 -23
  100. package/dist/runtime/types/flatpickr/ja.js +3 -37
  101. package/dist/runtime/types/toast.d.ts +1 -1
  102. package/dist/runtime/utils/dayjs.d.ts +8 -6
  103. package/dist/runtime/utils/dayjs.js +12 -5
  104. package/dist/runtime/utils/modal.d.ts +9 -28
  105. package/dist/runtime/utils/modal.js +7 -36
  106. package/dist/runtime/utils/multi-lang-object.d.ts +2 -2
  107. package/dist/runtime/utils/multi-lang-object.js +1 -5
  108. package/dist/runtime/utils/multi-lang.js +12 -22
  109. package/dist/runtime/utils/number.js +1 -1
  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 -118
  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 hover: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 hover:!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 hover:!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>