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,616 +1,453 @@
1
- <script setup lang="ts" generic="IdType extends string|number">
2
- /* ----------------------------------------------------------------------------
3
- // src\runtime\components\form\radio.vue
4
- // ----------------------------------------------------------------------------
5
- // Radio
6
- // RadioRadio
7
- ----------------------------------------------------------------------------- */
8
-
9
- // [ tailwind ]
10
- import { twMerge } from "tailwind-merge";
11
- // [ NUXT ]
12
- import {
13
- reactive,
14
- ref,
15
- watch,
16
- computed,
17
- useId,
18
- nextTick,
19
- type Ref,
20
- } from "#imports";
21
- // [ utils ]
22
- import { type ClassType, ClassTypeToString } from "../../utils/class-style";
23
- import type { SelectItem } from "../../utils/select-item";
24
- import { useDisplayList, type DisplaySelectItem } from "../../utils/select";
25
- import type { MultiLang } from "../../utils/multi-lang";
26
- import { ObjectCopy } from "../../utils/object";
27
-
28
- // [ composables ]
29
- import { useHsFocus } from "../../composables/use-hs-focus";
30
- import { useHsMultiLang } from "../../composables/use-hs-multi-lang";
31
- // [ Components ]
32
- import InputFrame from "./input-frame.vue";
33
- import SelectImgIcon from "./select-img-icon.vue";
34
- import Btn from "../form/btn.vue";
35
-
36
- // ----------------------------------------------------------------------------
37
- const hsFocus = useHsFocus();
38
- const multiLang = useHsMultiLang();
39
- const tx = multiLang.tx;
40
- const gt = multiLang.gt;
41
- // ----------------------------------------------------------------------------
42
- // [ Props ]
43
- type Props = {
44
- // ----------------------------------------------------------------------------
45
- // Input 種類別
46
- list: SelectItem<IdType>[];
47
- order?: boolean;
48
- image?: boolean;
49
- loading?: boolean;
50
- nullText?: MultiLang;
51
- classCol?: ClassType;
52
- classRow?: ClassType;
53
- classImg?: ClassType;
54
- classImgTag?: ClassType;
55
- nullable?: boolean;
56
- // ----------------------------------------------------------------------------
57
- data: IdType | null;
58
- diff?: IdType | null | undefined;
59
- tabindex?: string | undefined;
60
- // ----------------------------------------------------------------------------
61
- class?: ClassType;
62
- classHeader?: ClassType;
63
- classInput?: ClassType;
64
- // ----------------------------------------------------------------------------
65
- // 状態
66
- // focus?: boolean;
67
- focusColor?: string;
68
- // change?: boolean;
69
- changeColor?: string;
70
- error?: boolean;
71
- errorColor?: string;
72
- disabled?: boolean;
73
- disabledColor?: string;
74
- readonly?: boolean;
75
- headerless?: boolean;
76
- // ----------------------------------------------------------------------------
77
- // 表示
78
- label?: MultiLang;
79
- // 表示-副情報
80
- require?: boolean;
81
- requireText?: MultiLang;
82
- warn?: string;
83
- warnTimeOut?: number;
84
- // ----------------------------------------------------------------------------
85
- // 設定
86
- size?: "s" | "m" | "l";
87
- };
88
-
89
- const props = withDefaults(defineProps<Props>(), {
90
- // ----------------------------------------------------------------------------
91
- // Input 種類別
92
- order: false,
93
- image: false,
94
- loading: false,
95
- nullText: () => ({ ja: "選択してください", en: "Select..." }),
96
- nullable: false,
97
- classCol: "",
98
- classRow: "",
99
- classImg: "",
100
- classImgTag: "",
101
- // ----------------------------------------------------------------------------
102
- diff: undefined,
103
- tabindex: undefined,
104
- // ----------------------------------------------------------------------------
105
- class: "",
106
- classHeader: "",
107
- classInput: "",
108
- // ----------------------------------------------------------------------------
109
- // 状態
110
- // focus: false,
111
- focusColor: "shadow-[inset_0px_0px_1px_2px_#0d8ee4]",
112
- // change: false,
113
- changeColor: "shadow-[inset_0px_0px_1px_2px_#fd9831be]",
114
- error: false,
115
- errorColor: "shadow-[inset_0px_0px_1px_2px_#d80000dc]",
116
- disabled: false,
117
- disabledColor: "",
118
- readonly: false,
119
- headerless: false,
120
- // ----------------------------------------------------------------------------
121
- // 表示
122
- label: "",
123
- // 表示-副情報
124
- require: false,
125
- requireText: () => ({ ja: "必須", en: "Required" }),
126
- warn: "",
127
- warnTimeOut: 3000,
128
- // ----------------------------------------------------------------------------
129
- // 設定
130
- size: "m",
131
- });
132
- type EmitIdType = IdType extends string ? string : number;
133
- // ----------------------------------------------------------------------------
134
- // [ emit ]
135
- type Emits = {
136
- ref: [element: HTMLElement];
137
- focus: [elm: HTMLElement];
138
- blur: [elm: HTMLElement];
139
- // ----------------------------
140
- "update:data": [value: EmitIdType | null];
141
- "value-change": [after: EmitIdType | null, before: EmitIdType | null];
142
- // ----------------------------
143
- keydown: [event: KeyboardEvent];
144
- keyup: [event: KeyboardEvent];
145
- // ----------------------------
146
- };
147
- const emit = defineEmits<Emits>();
148
- // ----------------------------------------------------------------------------
149
- const slots = defineSlots<{
150
- default(props: { msg: string }): any;
151
- overlay?(): any;
152
- "right-icons"?(): any;
153
- "left-icons"?(): any;
154
- }>();
155
- // ----------------------------------------------------------------------------
156
- // [ getCurrentInstance ]
157
- const uid = useId();
158
- // ----------------------------------------------------------------------------
159
- // 更新の有無判定
160
- const isChangeData = computed(() => {
161
- if (props.diff === undefined) return false;
162
- if (props.diff !== props.data) return true;
163
- return false;
164
- });
165
- // [ ref ]
166
-
167
- // ----------------------------------------------------------------------------
168
- const displayData = ref<DisplaySelectItem<IdType> | null>(null);
169
- watch(displayData, (v) => {
170
- const before = props.data;
171
- if (v === null) {
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
- emit("update:data", v.id as any as EmitIdType | null);
181
- emit(
182
- "value-change",
183
- v.id as any as EmitIdType | null,
184
- before as any as EmitIdType | null
185
- );
186
- });
187
- const selectedId = computed(() => {
188
- // console.log("selectedId", displayData.value);
189
- if (displayData.value === null) {
190
- return null;
191
- }
192
- return displayData.value.id;
193
- });
194
- // ----------------------------------------------------------------------------
195
- // 不明選択肢太陽
196
- const unKnownSelected = ref<boolean>(false);
197
- const unKnownData = computed(() => {
198
- if (props.data === null) return null;
199
- return {
200
- id: props.data,
201
- text: {
202
- ja: `無効な値が選択されています (ID=${props.data})`,
203
- en: `Invalid value selected (ID=${props.data})`,
204
- },
205
- };
206
- });
207
-
208
- // ----------------------------------------------------------------------------
209
- const isShowHidden = ref(false);
210
- /** 選択肢に非表示アイテムが含まれているかどうか */
211
- const includeHidden = computed(() => {
212
- return props.list.filter((row) => row.hidden).length > 0;
213
- });
214
- // ----------------------------------------------------------------------------
215
- /** 選択肢 */
216
- interface SelectItemShow extends DisplaySelectItem<IdType> {
217
- elm: HTMLElement | null;
218
- activate: boolean;
219
- i: number;
220
- }
221
- const displayList: Ref<SelectItemShow[]> = ref([]);
222
-
223
- const baseList = computed(() => {
224
- return ObjectCopy(props.list).map((row) => {
225
- return { ...row, text: gt(row.text) };
226
- });
227
- });
228
-
229
- const setDisplayList = () => {
230
- displayList.value = useDisplayList<IdType>({
231
- list: baseList.value,
232
- id: props.data,
233
- order: props.order,
234
- unKnownData: unKnownData.value,
235
- unKnownSelected: unKnownSelected.value,
236
- isShowHidden: isShowHidden.value,
237
- require: props.require || !props.nullable,
238
- nullText: tx(props.nullText).value,
239
- }).map((row, index) => {
240
- return {
241
- ...row,
242
- elm: null,
243
- activate: false,
244
- i: index,
245
- };
246
- }) as SelectItemShow[];
247
- };
248
- watch(
249
- () => props.list,
250
- () => {
251
- nextTick(() => {
252
- setDisplayList();
253
- });
254
- },
255
- { deep: true }
256
- );
257
-
258
- watch(
259
- () => [
260
- props.data,
261
- isShowHidden.value,
262
- props.require,
263
- props.nullable,
264
- props.nullText,
265
- unKnownSelected.value,
266
- displayData.value,
267
- ],
268
- () => {
269
- nextTick(() => {
270
- setDisplayList();
271
- });
272
- },
273
- { immediate: true }
274
- );
275
- // ----------------------------------------------------------------------------
276
-
277
- const checkData = (id: IdType | null) => {
278
- const ret = baseList.value.find((row) => row.id === id);
279
- if (ret === undefined) {
280
- // 選択肢に存在しないコード引当
281
- unKnownSelected.value = true;
282
- displayData.value = unKnownData.value;
283
- } else {
284
- unKnownSelected.value = false;
285
- displayData.value = ret;
286
- }
287
- };
288
- checkData(props.data);
289
- // const activateItem = computed(() => {
290
- watch(
291
- () => props.data,
292
- (id) => {
293
- checkData(id);
294
- }
295
- );
296
- watch(baseList, () => {
297
- // console.log("change list");
298
- nextTick(() => {
299
- checkData(props.data);
300
- });
301
- });
302
- // ----------------------------------------------------------------------------
303
-
304
- // [ focus, blur ]
305
- interface FocusState {
306
- isActivate: boolean;
307
- isMmousedownItem: boolean;
308
- isNullActivate: boolean;
309
- isKeyDown: boolean;
310
- }
311
- const focusState = reactive<FocusState>({
312
- isActivate: false,
313
- isMmousedownItem: false,
314
- isNullActivate: false,
315
- isKeyDown: false,
316
- });
317
-
318
- /**
319
- * コントロールのFocus判定
320
- */
321
- const computedActivate = computed(() => {
322
- if (props.disabled === true) return false;
323
- if (hsFocus.state.id !== uid) return false;
324
- if (focusState.isActivate) return true;
325
- if (focusState.isMmousedownItem) return true;
326
- if (focusState.isNullActivate) return true;
327
- if (focusState.isKeyDown) return true;
328
- if (displayList.value.filter((row) => row.activate === true).length === 1)
329
- return true;
330
- return false;
331
- });
332
-
333
- // ----------------------------------------------------------------------------
334
- // const isOpen = ref(false);
335
-
336
- const onFocus = (index: null | number) => {
337
- if (props.disabled) return;
338
- if (props.readonly) return;
339
- focusState.isActivate = true;
340
- if (index === null) {
341
- focusState.isNullActivate = true;
342
- } else {
343
- displayList.value[index].activate = true;
344
- }
345
- hsFocus.state.id = uid;
346
- };
347
-
348
- const onBlur = (index: null | number) => {
349
- if (props.disabled) return;
350
- if (props.readonly) return;
351
- if (index === null) {
352
- focusState.isNullActivate = false;
353
- } else if (index in displayList.value) {
354
- displayList.value[index].activate = false;
355
- }
356
- setTimeout(() => {
357
- focusState.isActivate = false;
358
- }, 5);
359
- };
360
- // ----------------------------------------------------------------------------
361
- const colClass = computed(() => {
362
- return twMerge(
363
- //
364
- "col-auto",
365
- ClassTypeToString(props.classCol)
366
- );
367
- });
368
- // ----------------------------------------------------------------------------
369
-
370
- const inputElementNull = ref<HTMLElement | null>(null);
371
- // ----------------------------------------------------------------------------
372
- const onMousedownItem = () => {
373
- if (props.disabled) return;
374
- if (props.readonly) return;
375
- focusState.isMmousedownItem = true;
376
- };
377
- const onMouseupItem = (elm: HTMLElement | null) => {
378
- if (props.disabled) return;
379
- if (props.readonly) return;
380
- focusState.isMmousedownItem = false;
381
- if (elm !== null) {
382
- elm.focus();
383
- }
384
- };
385
-
386
- const onKeydown = (event: KeyboardEvent) => {
387
- if (props.disabled || props.readonly) {
388
- event.preventDefault();
389
- return;
390
- }
391
- focusState.isKeyDown = true;
392
- };
393
-
394
- const onKeyup = (event: KeyboardEvent) => {
395
- if (props.disabled || props.readonly) {
396
- event.preventDefault();
397
- return;
398
- }
399
- focusState.isKeyDown = false;
400
- };
401
-
402
- const setValue = async (row: SelectItemShow | null) => {
403
- if (props.disabled) return;
404
- if (props.readonly) return;
405
- // console.log(row);
406
- displayData.value = row;
407
- };
408
-
409
- // ----------------------------------------------------------------------------
410
- const baseClass = computed(() => {
411
- return [
412
- twMerge(
413
- //
414
- "h-auto",
415
- props.size === "s" ? "min-h-[44px] " : "",
416
- props.size === "m" ? "min-h-[48px]" : "",
417
- props.size === "l" ? "min-h-[60px]" : "",
418
- ClassTypeToString(props.class)
419
- ),
420
- ];
421
- });
422
- // ----------------------------------------------------------------------------
423
- const inputClass = computed(() => {
424
- return [
425
- twMerge(
426
- //
427
- "px-2",
428
- ClassTypeToString(props.classInput)
429
- ),
430
- ];
431
- });
432
-
433
- // ----------------------------------------------------------------------------
434
- </script>
435
-
436
- <template>
437
- <InputFrame
438
- :class="baseClass"
439
- :class-header="props.classHeader"
440
- :class-input="inputClass"
441
- :focus="computedActivate"
442
- :focus-color="props.focusColor"
443
- :change="isChangeData"
444
- :change-color="props.changeColor"
445
- :error="props.error"
446
- :error-color="props.errorColor"
447
- :disabled="props.disabled"
448
- :disabled-color="props.disabledColor"
449
- :readonly="props.readonly"
450
- :label="props.label"
451
- :require="props.require"
452
- :require-text="tx(props.requireText).value"
453
- :warn="props.warn"
454
- :warn-time-out="props.warnTimeOut"
455
- :size="props.size"
456
- :headerless="props.headerless"
457
- >
458
- <template v-if="slots['left-icons']" #left-icons>
459
- <slot name="left-icons" :disabled="disabled" />
460
- </template>
461
- <template v-if="slots['right-icons']" #right-icons>
462
- <slot name="right-icons" :disabled="disabled" />
463
- </template>
464
- <template v-if="slots.overlay" #overlay>
465
- <slot name="overlay"></slot>
466
- </template>
467
- <div class="nac-input">
468
- <div
469
- class="radio-row"
470
- :class="[`flex flex-wrap`, classRow]"
471
- @keyup.up="onKeyup"
472
- @keydown.up="onKeydown"
473
- @keyup.down="onKeyup"
474
- @keydown.down="onKeydown"
475
- @keyup.left="onKeyup"
476
- @keydown.left="onKeydown"
477
- @keyup.right="onKeyup"
478
- @keydown.right="onKeydown"
479
- >
480
- <!-- null -->
481
- <div
482
- v-if="!props.require && props.nullable"
483
- class="radio-col"
484
- :class="colClass"
485
- >
486
- <div
487
- class="nac-radio"
488
- :class="[{ disabled: props.disabled, readonly: props.readonly }]"
489
- @mousedown="onMousedownItem"
490
- @mouseup="onMouseupItem(inputElementNull)"
491
- @click="setValue(null)"
492
- >
493
- <input
494
- :id="`radio${uid}-null`"
495
- :ref="(e:any) => (inputElementNull = e)"
496
- type="radio"
497
- :name="`radio${uid}`"
498
- :tabindex="props.tabindex"
499
- :value="null"
500
- :disabled="props.disabled"
501
- :readonly="props.readonly"
502
- @focus="onFocus(null)"
503
- @blur="onBlur(null)"
504
- />
505
- <div
506
- class="radio-mark"
507
- :class="[{ checked: selectedId === null }]"
508
- ></div>
509
- <div class="radio-label">
510
- <SelectImgIcon
511
- v-if="props.image"
512
- class="flex-none"
513
- :img-url="null"
514
- :class-img="props.classImg"
515
- :class-img-tag="props.classImgTag"
516
- />
517
- <div class="radio-text truncate">{{ tx(nullText) }}</div>
518
- </div>
519
- </div>
520
- </div>
521
- <!-- list -->
522
- <template v-for="(row, index) in displayList" :key="index">
523
- <div
524
- v-if="row.id !== null"
525
- class="radio-col"
526
- :class="colClass"
527
- @mousedown="onMousedownItem"
528
- @mouseup="onMouseupItem(row.elm)"
529
- @click="setValue(row)"
530
- >
531
- <div
532
- class="nac-radio"
533
- :class="[{ disabled: props.disabled, readonly: props.readonly }]"
534
- >
535
- <input
536
- :id="`radio${uid}-${row.id}`"
537
- :ref="(e:any) => (row.elm = e)"
538
- type="radio"
539
- class=""
540
- :name="`radio${uid}`"
541
- :tabindex="props.tabindex"
542
- :value="row.id"
543
- :disabled="props.disabled"
544
- :readonly="props.readonly"
545
- @focus="onFocus(index)"
546
- @blur="onBlur(index)"
547
- />
548
- <div
549
- class="radio-mark"
550
- :class="[{ checked: selectedId === row.id }]"
551
- ></div>
552
- <div
553
- class="radio-label"
554
- :class="{
555
- isDeleted: row.deleted === true,
556
- isHidden: row.hidden === false,
557
- }"
558
- >
559
- <SelectImgIcon
560
- v-if="props.image"
561
- class="flex-none"
562
- :img-url="row.imgUrl"
563
- :class-img="props.classImg"
564
- :class-img-tag="props.classImgTag"
565
- />
566
- <div class="radio-text truncate">
567
- {{ tx(row.text) }}
568
- <span
569
- v-if="row.deleted"
570
- class="text-error text-[0.7em] leading-[1em]"
571
- >
572
- {{ tx({ ja: "削除済", en: "Deleted" }) }}
573
- </span>
574
- <span
575
- v-if="row.hidden"
576
- class="text-error text-[0.7em] leading-[1em]"
577
- >
578
- {{ tx({ ja: "非表示", en: "Hidden" }) }}
579
- </span>
580
- </div>
581
- </div>
582
- </div>
583
- </div>
584
- </template>
585
- </div>
586
- <template v-if="includeHidden">
587
- <Btn
588
- theme="accent1"
589
- variant="outlined"
590
- class="w-full mb-1"
591
- size="xs"
592
- @click="isShowHidden = !isShowHidden"
593
- >
594
- <span class="me-1">Hidden options</span>
595
- <i
596
- class="fas"
597
- :class="[
598
- !isShowHidden ? 'fa-eye-slash text-error' : 'fa-eye text-success',
599
- ]"
600
- ></i>
601
- <i class="fas fa-caret-right mx-1"></i>
602
- <i
603
- class="fas"
604
- :class="[
605
- isShowHidden ? 'fa-eye-slash text-error' : 'fa-eye text-success',
606
- ]"
607
- ></i>
608
- </Btn>
609
- </template>
610
- </div>
611
- </InputFrame>
612
- </template>
613
-
1
+ <script setup>
2
+ import { twMerge } from "tailwind-merge";
3
+ import { reactive, ref, watch, computed, useId, nextTick } from "#imports";
4
+ import { ClassTypeToString } from "../../utils/class-style";
5
+ import { useDisplayList } from "../../utils/select";
6
+ import { ObjectCopy } from "../../utils/object";
7
+ import { useHsFocus } from "../../composables/use-hs-focus";
8
+ import { useHsMultiLang } from "../../composables/use-hs-multi-lang";
9
+ import { useHsPinia } from "../../composables/use-pinia";
10
+ import { useHsMisc } from "../../composables/use-hs-misc";
11
+ import InputFrame from "./input-frame.vue";
12
+ import SelectImgIcon from "./select-img-icon.vue";
13
+ import Btn from "../form/btn.vue";
14
+ const hsFocus = useHsFocus(useHsPinia());
15
+ const multiLang = useHsMultiLang(useHsPinia());
16
+ const hsMisc = useHsMisc(useHsPinia());
17
+ const tx = multiLang.tx;
18
+ const gt = multiLang.gt;
19
+ const props = defineProps({
20
+ list: { type: Array, required: true },
21
+ order: { type: Boolean, required: false, default: false },
22
+ image: { type: Boolean, required: false, default: false },
23
+ loading: { type: Boolean, required: false, default: false },
24
+ nullText: { type: [String, Object], required: false, default: () => ({ ja: "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044", en: "Select..." }) },
25
+ classCol: { type: [String, Object, Array], required: false, default: "" },
26
+ classRow: { type: [String, Object, Array], required: false, default: "" },
27
+ classImg: { type: [String, Object, Array], required: false, default: "" },
28
+ classImgTag: { type: [String, Object, Array], required: false, default: "" },
29
+ nullable: { type: Boolean, required: false, default: false },
30
+ data: { type: null, required: true },
31
+ diff: { type: null, required: false, default: void 0 },
32
+ tabindex: { type: null, required: false, default: void 0 },
33
+ class: { type: [String, Object, Array], required: false, default: "" },
34
+ classHeader: { type: [String, Object, Array], required: false, default: "" },
35
+ classInput: { type: [String, Object, Array], required: false, default: "" },
36
+ focusColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#0d8ee4]" },
37
+ changeColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#fd9831be]" },
38
+ error: { type: Boolean, required: false, default: false },
39
+ errorColor: { type: String, required: false, default: "shadow-[inset_0px_0px_1px_2px_#d80000dc]" },
40
+ disabled: { type: Boolean, required: false, default: false },
41
+ disabledColor: { type: String, required: false, default: "" },
42
+ readonly: { type: Boolean, required: false, default: false },
43
+ headerless: { type: Boolean, required: false, default: false },
44
+ label: { type: [String, Object], required: false, default: "" },
45
+ require: { type: Boolean, required: false, default: false },
46
+ requireText: { type: [String, Object], required: false, default: () => ({ ja: "\u5FC5\u9808", en: "Required" }) },
47
+ warn: { type: String, required: false, default: "" },
48
+ warnTimeOut: { type: Number, required: false, default: 3e3 },
49
+ size: { type: String, required: false, default: "m" }
50
+ });
51
+ const emit = defineEmits(["ref", "focus", "blur", "update:data", "value-change", "keydown", "keyup"]);
52
+ const slots = defineSlots();
53
+ const uid = useId();
54
+ const isChangeData = computed(() => {
55
+ if (props.diff === void 0) return false;
56
+ if (props.diff !== props.data) return true;
57
+ return false;
58
+ });
59
+ const displayData = ref(null);
60
+ watch(displayData, (v) => {
61
+ const before = props.data;
62
+ if (v === null) {
63
+ emit("update:data", null);
64
+ emit("value-change", null, before);
65
+ return;
66
+ }
67
+ if (v.id === null) {
68
+ displayData.value = null;
69
+ return;
70
+ }
71
+ emit("update:data", v.id);
72
+ emit("value-change", v.id, before);
73
+ });
74
+ const selectedId = computed(() => {
75
+ if (displayData.value === null) {
76
+ return null;
77
+ }
78
+ return displayData.value.id;
79
+ });
80
+ const unKnownSelected = ref(false);
81
+ const unKnownData = computed(() => {
82
+ if (props.data === null) return null;
83
+ return {
84
+ id: props.data,
85
+ text: {
86
+ ja: `\u7121\u52B9\u306A\u5024\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u3059 (ID=${props.data})`,
87
+ en: `Invalid value selected (ID=${props.data})`
88
+ }
89
+ };
90
+ });
91
+ const isShowHidden = ref(false);
92
+ const includeHidden = computed(() => {
93
+ return props.list.filter((row) => row.hidden).length > 0;
94
+ });
95
+ const displayList = ref([]);
96
+ const baseList = computed(() => {
97
+ return ObjectCopy(props.list).map((row) => {
98
+ return { ...row, text: gt(row.text) };
99
+ });
100
+ });
101
+ const diffDisplayText = computed(() => {
102
+ if (!props.diff) return "";
103
+ const data = baseList.value.find((row) => row.id === props.diff) || null;
104
+ if (!data) return props.nullText;
105
+ return tx(data.text).value;
106
+ });
107
+ const setDisplayList = () => {
108
+ displayList.value = useDisplayList({
109
+ list: baseList.value,
110
+ id: props.data,
111
+ order: props.order,
112
+ unKnownData: unKnownData.value,
113
+ unKnownSelected: unKnownSelected.value,
114
+ isShowHidden: isShowHidden.value,
115
+ require: props.require || !props.nullable,
116
+ nullText: tx(props.nullText).value
117
+ }).map((row, index) => {
118
+ return {
119
+ ...row,
120
+ elm: null,
121
+ activate: false,
122
+ i: index
123
+ };
124
+ });
125
+ };
126
+ watch(
127
+ () => props.list,
128
+ () => {
129
+ nextTick(() => {
130
+ setDisplayList();
131
+ });
132
+ },
133
+ { deep: true }
134
+ );
135
+ watch(
136
+ () => [
137
+ props.data,
138
+ isShowHidden.value,
139
+ props.require,
140
+ props.nullable,
141
+ props.nullText,
142
+ unKnownSelected.value,
143
+ displayData.value,
144
+ multiLang.lang
145
+ ],
146
+ () => {
147
+ nextTick(() => {
148
+ setDisplayList();
149
+ });
150
+ },
151
+ { immediate: true }
152
+ );
153
+ const checkData = (id) => {
154
+ const ret = baseList.value.find((row) => row.id === id);
155
+ if (ret === void 0) {
156
+ unKnownSelected.value = true;
157
+ displayData.value = unKnownData.value;
158
+ } else {
159
+ unKnownSelected.value = false;
160
+ displayData.value = ret;
161
+ }
162
+ };
163
+ checkData(props.data);
164
+ watch(
165
+ () => props.data,
166
+ (id) => {
167
+ checkData(id);
168
+ }
169
+ );
170
+ watch(baseList, () => {
171
+ nextTick(() => {
172
+ checkData(props.data);
173
+ });
174
+ });
175
+ const focusState = reactive({
176
+ isActivate: false,
177
+ isMmousedownItem: false,
178
+ isNullActivate: false,
179
+ isKeyDown: false
180
+ });
181
+ const computedActivate = computed(() => {
182
+ if (props.disabled === true) return false;
183
+ if (hsFocus.state.id !== uid) return false;
184
+ if (focusState.isActivate) return true;
185
+ if (focusState.isMmousedownItem) return true;
186
+ if (focusState.isNullActivate) return true;
187
+ if (focusState.isKeyDown) return true;
188
+ if (displayList.value.filter((row) => row.activate === true).length === 1) return true;
189
+ return false;
190
+ });
191
+ const onFocus = (index) => {
192
+ if (props.disabled) return;
193
+ if (props.readonly) return;
194
+ focusState.isActivate = true;
195
+ if (index === null) {
196
+ focusState.isNullActivate = true;
197
+ } else if (index in displayList.value && displayList.value[index]) {
198
+ displayList.value[index].activate = true;
199
+ }
200
+ hsFocus.state.id = uid;
201
+ };
202
+ const onBlur = (index) => {
203
+ if (props.disabled) return;
204
+ if (props.readonly) return;
205
+ if (index === null) {
206
+ focusState.isNullActivate = false;
207
+ } else if (index in displayList.value && displayList.value[index]) {
208
+ displayList.value[index].activate = false;
209
+ }
210
+ setTimeout(() => {
211
+ focusState.isActivate = false;
212
+ }, 5);
213
+ };
214
+ const colClass = computed(() => {
215
+ return twMerge(
216
+ //
217
+ "col-auto",
218
+ ClassTypeToString(props.classCol)
219
+ );
220
+ });
221
+ const inputElementNull = ref(null);
222
+ const onMousedownItem = () => {
223
+ if (props.disabled) return;
224
+ if (props.readonly) return;
225
+ focusState.isMmousedownItem = true;
226
+ };
227
+ const onMouseupItem = (elm) => {
228
+ if (props.disabled) return;
229
+ if (props.readonly) return;
230
+ focusState.isMmousedownItem = false;
231
+ if (elm !== null) {
232
+ elm.focus();
233
+ }
234
+ };
235
+ const onKeydown = (event) => {
236
+ if (props.disabled || props.readonly) {
237
+ event.preventDefault();
238
+ return;
239
+ }
240
+ focusState.isKeyDown = true;
241
+ };
242
+ const onKeyup = (event) => {
243
+ if (props.disabled || props.readonly) {
244
+ event.preventDefault();
245
+ return;
246
+ }
247
+ focusState.isKeyDown = false;
248
+ };
249
+ const setValue = async (row) => {
250
+ if (props.disabled) return;
251
+ if (props.readonly) return;
252
+ displayData.value = row;
253
+ };
254
+ const baseClass = computed(() => {
255
+ return [
256
+ twMerge(
257
+ //
258
+ "h-auto",
259
+ props.size === "s" ? "min-h-[44px] " : "",
260
+ props.size === "m" ? "min-h-[48px]" : "",
261
+ props.size === "l" ? "min-h-[60px]" : "",
262
+ ClassTypeToString(props.class)
263
+ )
264
+ ];
265
+ });
266
+ const inputClass = computed(() => {
267
+ return [
268
+ twMerge(
269
+ //
270
+ "px-2",
271
+ ClassTypeToString(props.classInput)
272
+ )
273
+ ];
274
+ });
275
+ </script>
276
+
277
+ <template>
278
+ <InputFrame
279
+ :class="baseClass"
280
+ :class-header="props.classHeader"
281
+ :class-input="inputClass"
282
+ :focus="computedActivate"
283
+ :focus-color="props.focusColor"
284
+ :change="isChangeData"
285
+ :change-color="props.changeColor"
286
+ :error="props.error"
287
+ :error-color="props.errorColor"
288
+ :disabled="props.disabled"
289
+ :disabled-color="props.disabledColor"
290
+ :readonly="props.readonly"
291
+ :label="props.label"
292
+ :require="props.require"
293
+ :require-text="tx(props.requireText).value"
294
+ :warn="props.warn"
295
+ :warn-time-out="props.warnTimeOut"
296
+ :size="props.size"
297
+ :headerless="props.headerless"
298
+ >
299
+ <template #overlay="{ focus, change }">
300
+ <div
301
+ v-if="props.diff !== void 0 && change"
302
+ class="absolute inset-0 bg-red/30 transition-opacity flex items-center p-1 bg-dark/20"
303
+ :class="!focus && hsMisc.capsLockState ? 'opacity-100' : 'opacity-0 pointer-events-none select-none'"
304
+ >
305
+ <div class="flex">
306
+ <Btn
307
+ variant="outlined"
308
+ theme="error"
309
+ tabindex="-1"
310
+ size="xs"
311
+ class="bg-white flex-none"
312
+ @click="checkData(props.diff)"
313
+ >
314
+ <i class="fa-solid fa-rotate-right"></i>
315
+ </Btn>
316
+ <div v-if="props.diff" class="px-1 truncate bg-white mx-1 flex items-center">{{ diffDisplayText }}</div>
317
+ </div>
318
+ </div>
319
+ <template v-if="slots.overlay">
320
+ <slot name="overlay" :focus="focus" :change="change"></slot>
321
+ </template>
322
+ </template>
323
+ <template v-if="slots['left-icons']" #left-icons>
324
+ <slot name="left-icons" :disabled="disabled" />
325
+ </template>
326
+ <template v-if="slots['right-icons']" #right-icons>
327
+ <slot name="right-icons" :disabled="disabled" />
328
+ </template>
329
+ <template v-if="slots['label-prepend']" #label-prepend>
330
+ <slot name="label-prepend" />
331
+ </template>
332
+ <template v-if="slots['label-append']" #label-append>
333
+ <slot name="label-append" />
334
+ </template>
335
+ <template v-if="slots['header-right']" #header-right>
336
+ <slot name="header-right" />
337
+ </template>
338
+
339
+ <div class="nac-input">
340
+ <div
341
+ class="radio-row"
342
+ :class="[`flex flex-wrap`, classRow]"
343
+ @keyup.up="onKeyup"
344
+ @keydown.up="onKeydown"
345
+ @keyup.down="onKeyup"
346
+ @keydown.down="onKeydown"
347
+ @keyup.left="onKeyup"
348
+ @keydown.left="onKeydown"
349
+ @keyup.right="onKeyup"
350
+ @keydown.right="onKeydown"
351
+ >
352
+ <!-- null -->
353
+ <div v-if="!props.require && props.nullable" class="radio-col" :class="colClass">
354
+ <div
355
+ class="nac-radio"
356
+ :class="[{ disabled: props.disabled, readonly: props.readonly }]"
357
+ @mousedown="onMousedownItem"
358
+ @mouseup="onMouseupItem(inputElementNull)"
359
+ @click="setValue(null)"
360
+ >
361
+ <input
362
+ :id="`radio${uid}-null`"
363
+ :ref="(e) => inputElementNull = e"
364
+ type="radio"
365
+ :name="`radio${uid}`"
366
+ :tabindex="props.tabindex"
367
+ :value="null"
368
+ :disabled="props.disabled"
369
+ :readonly="props.readonly"
370
+ @focus="onFocus(null)"
371
+ @blur="onBlur(null)"
372
+ />
373
+ <div class="radio-mark" :class="[{ checked: selectedId === null }]"></div>
374
+ <div class="radio-label">
375
+ <SelectImgIcon
376
+ v-if="props.image"
377
+ class="flex-none"
378
+ :img-url="null"
379
+ :class-img="props.classImg"
380
+ :class-img-tag="props.classImgTag"
381
+ />
382
+ <div class="radio-text truncate">{{ tx(nullText) }}</div>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ <!-- list -->
387
+ <template v-for="(row, index) in displayList" :key="index">
388
+ <div
389
+ v-if="row.id !== null"
390
+ class="radio-col"
391
+ :class="colClass"
392
+ @mousedown="onMousedownItem"
393
+ @mouseup="onMouseupItem(row.elm)"
394
+ @click="setValue(row)"
395
+ >
396
+ <div class="nac-radio" :class="[{ disabled: props.disabled, readonly: props.readonly }]">
397
+ <input
398
+ :id="`radio${uid}-${row.id}`"
399
+ :ref="(e) => row.elm = e"
400
+ type="radio"
401
+ class=""
402
+ :name="`radio${uid}`"
403
+ :tabindex="props.tabindex"
404
+ :value="row.id"
405
+ :disabled="props.disabled"
406
+ :readonly="props.readonly"
407
+ @focus="onFocus(index)"
408
+ @blur="onBlur(index)"
409
+ />
410
+ <div class="radio-mark" :class="[{ checked: selectedId === row.id }]"></div>
411
+ <div
412
+ class="radio-label"
413
+ :class="{
414
+ isDeleted: row.deleted === true,
415
+ isHidden: row.hidden === false
416
+ }"
417
+ >
418
+ <SelectImgIcon
419
+ v-if="props.image"
420
+ class="flex-none"
421
+ :img-url="row.imgUrl"
422
+ :class-img="props.classImg"
423
+ :class-img-tag="props.classImgTag"
424
+ />
425
+ <div class="radio-text truncate">
426
+ {{ tx(row.text) }}
427
+ <span v-if="row.deleted" class="text-error text-[0.7em] leading-[1em]">
428
+ {{ tx({ ja: "\u524A\u9664\u6E08", en: "Deleted" }) }}
429
+ </span>
430
+ <span v-if="row.hidden" class="text-error text-[0.7em] leading-[1em]">
431
+ {{ tx({ ja: "\u975E\u8868\u793A", en: "Hidden" }) }}
432
+ </span>
433
+ </div>
434
+ </div>
435
+ </div>
436
+ </div>
437
+ </template>
438
+ </div>
439
+ <template v-if="includeHidden">
440
+ <Btn theme="accent1" variant="outlined" class="w-full mb-1" size="xs" @click="isShowHidden = !isShowHidden">
441
+ <span class="me-1">Hidden options</span>
442
+ <i class="fas" :class="[!isShowHidden ? 'fa-eye-slash text-error' : 'fa-eye text-success']"></i>
443
+ <i class="fas fa-caret-right mx-1"></i>
444
+ <i class="fas" :class="[isShowHidden ? 'fa-eye-slash text-error' : 'fa-eye text-success']"></i>
445
+ </Btn>
446
+ </template>
447
+ </div>
448
+ </InputFrame>
449
+ </template>
450
+
614
451
  <style>
615
452
  .nac-input {
616
453
  width: 100%;
@@ -774,4 +611,4 @@ const inputClass = computed(() => {
774
611
  .nac-input.disabled .item-hidden-control i {
775
612
  color: rgb(92, 92, 92) !important;
776
613
  }
777
- </style>
614
+ </style>