@sfxcode/formkit-openvue 0.0.0-stage → 0.9.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.
- package/LICENSE +21 -0
- package/README.md +227 -2
- package/components.d.ts +1 -0
- package/dist/components/FormAutoComplete.vue +100 -0
- package/dist/components/FormCascadeSelect.vue +41 -0
- package/dist/components/FormCheckbox.vue +49 -0
- package/dist/components/FormColorPicker.vue +31 -0
- package/dist/components/FormDatePicker.vue +93 -0
- package/dist/components/FormInputMask.vue +67 -0
- package/dist/components/FormInputNumber.vue +72 -0
- package/dist/components/FormInputOtp.vue +40 -0
- package/dist/components/FormInputText.vue +63 -0
- package/dist/components/FormKitDataDebug.vue +25 -0
- package/dist/components/FormKitDataEdit.vue +123 -0
- package/dist/components/FormKitDataView.vue +56 -0
- package/dist/components/FormKitIcon.vue +23 -0
- package/dist/components/FormKitPrefix.vue +9 -0
- package/dist/components/FormKitSuffix.vue +9 -0
- package/dist/components/FormKnob.vue +48 -0
- package/dist/components/FormListbox.vue +482 -0
- package/dist/components/FormMultiSelect.vue +68 -0
- package/dist/components/FormOutputBoolean.vue +30 -0
- package/dist/components/FormOutputDate.vue +40 -0
- package/dist/components/FormOutputDuration.vue +24 -0
- package/dist/components/FormOutputLink.vue +39 -0
- package/dist/components/FormOutputList.vue +105 -0
- package/dist/components/FormOutputNumber.vue +47 -0
- package/dist/components/FormOutputReference.vue +52 -0
- package/dist/components/FormOutputText.vue +52 -0
- package/dist/components/FormPassword.vue +47 -0
- package/dist/components/FormRadioButton.vue +39 -0
- package/dist/components/FormRating.vue +38 -0
- package/dist/components/FormSelect.vue +69 -0
- package/dist/components/FormSelectButton.vue +42 -0
- package/dist/components/FormSlider.vue +40 -0
- package/dist/components/FormTextarea.vue +35 -0
- package/dist/components/FormToggleButton.vue +40 -0
- package/dist/components/FormToggleSwitch.vue +40 -0
- package/dist/components/FormTreeSelect.vue +46 -0
- package/dist/components/index.d.ts +24 -0
- package/dist/components/index.js +167 -0
- package/dist/components/index.mjs +48 -0
- package/dist/composables/index.d.ts +9 -0
- package/dist/composables/index.js +61 -0
- package/dist/composables/index.mjs +18 -0
- package/dist/composables/useFormInputs.d.ts +3 -0
- package/dist/composables/useFormInputs.js +62 -0
- package/dist/composables/useFormInputs.mjs +53 -0
- package/dist/composables/useFormKitInput.d.ts +11 -0
- package/dist/composables/useFormKitInput.js +58 -0
- package/dist/composables/useFormKitInput.mjs +45 -0
- package/dist/composables/useFormKitRepeater.d.ts +18 -0
- package/dist/composables/useFormKitRepeater.js +74 -0
- package/dist/composables/useFormKitRepeater.mjs +54 -0
- package/dist/composables/useFormKitSchema.d.ts +36 -0
- package/dist/composables/useFormKitSchema.js +83 -0
- package/dist/composables/useFormKitSchema.mjs +58 -0
- package/dist/composables/useFormKitSection.d.ts +7 -0
- package/dist/composables/useFormKitSection.js +31 -0
- package/dist/composables/useFormKitSection.mjs +19 -0
- package/dist/composables/useInputEditor.d.ts +8 -0
- package/dist/composables/useInputEditor.js +148 -0
- package/dist/composables/useInputEditor.mjs +143 -0
- package/dist/composables/useInputEditorSchema.d.ts +163 -0
- package/dist/composables/useInputEditorSchema.js +313 -0
- package/dist/composables/useInputEditorSchema.mjs +315 -0
- package/dist/composables/useOutputDuration.d.ts +4 -0
- package/dist/composables/useOutputDuration.js +40 -0
- package/dist/composables/useOutputDuration.mjs +35 -0
- package/dist/definitions/index.d.ts +35 -0
- package/dist/definitions/index.js +44 -0
- package/dist/definitions/index.mjs +70 -0
- package/dist/definitions/input.d.ts +23 -0
- package/dist/definitions/input.js +118 -0
- package/dist/definitions/input.mjs +111 -0
- package/dist/definitions/output.d.ts +9 -0
- package/dist/definitions/output.js +46 -0
- package/dist/definitions/output.mjs +136 -0
- package/dist/definitions/repeater.d.ts +2 -0
- package/dist/definitions/repeater.js +234 -0
- package/dist/definitions/repeater.mjs +215 -0
- package/dist/index.d.ts +148 -0
- package/dist/index.js +62 -0
- package/dist/index.mjs +14 -0
- package/dist/plugins/autoAnimate.d.ts +9 -0
- package/dist/plugins/autoAnimate.js +93 -0
- package/dist/plugins/autoAnimate.mjs +87 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.js +67 -0
- package/dist/plugins/index.mjs +56 -0
- package/dist/sass/formkit-openvue.scss +491 -0
- package/dist/style.css +1 -0
- package/dist/utils/clonePlain.d.ts +10 -0
- package/dist/utils/clonePlain.js +25 -0
- package/dist/utils/clonePlain.mjs +24 -0
- package/package.json +136 -4
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { useFormKitInput } from "../composables";
|
|
4
|
+
const props = defineProps({ context: {
|
|
5
|
+
type: Object,
|
|
6
|
+
required: true
|
|
7
|
+
} });
|
|
8
|
+
const { validSlotNames, unstyled, isInvalid, handleInput, handleBlur, handleChange, modelValue } = useFormKitInput(props.context);
|
|
9
|
+
// Computed properties for transfer mode styling
|
|
10
|
+
const transferContainerClass = computed(() => {
|
|
11
|
+
return props.context.transferContainerClass || "p-formkit-transfer";
|
|
12
|
+
});
|
|
13
|
+
const transferListContainerClass = computed(() => {
|
|
14
|
+
return props.context.transferListContainerClass || "p-formkit-transfer-list-container";
|
|
15
|
+
});
|
|
16
|
+
const transferButtonClass = computed(() => {
|
|
17
|
+
return props.context.transferButtonClass || "";
|
|
18
|
+
});
|
|
19
|
+
const transferButtonSeverity = computed(() => {
|
|
20
|
+
return props.context.transferButtonSeverity || "secondary";
|
|
21
|
+
});
|
|
22
|
+
const transferDragDrop = computed(() => {
|
|
23
|
+
return props.context.transferDragDrop ?? true;
|
|
24
|
+
});
|
|
25
|
+
const transferSlotNames = computed(() => {
|
|
26
|
+
return validSlotNames.value.filter((slotName) => slotName !== "option");
|
|
27
|
+
});
|
|
28
|
+
// Transfer List functionality
|
|
29
|
+
const optionValueKey = computed(() => {
|
|
30
|
+
const key = props.context.optionValue;
|
|
31
|
+
return typeof key === "string" ? key : null;
|
|
32
|
+
});
|
|
33
|
+
// Helper function to convert values to full objects
|
|
34
|
+
function valuesToObjects(values) {
|
|
35
|
+
if (!optionValueKey.value) return values;
|
|
36
|
+
const options = props.context?.options || [];
|
|
37
|
+
return values.map((val) => {
|
|
38
|
+
if (typeof val === "object") return val;
|
|
39
|
+
return options.find((opt) => opt[optionValueKey.value] === val) || val;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// Initialize targetItems by converting any values to full objects
|
|
43
|
+
const initialTargetItems = Array.isArray(modelValue.value) ? valuesToObjects(modelValue.value) : [];
|
|
44
|
+
const targetItems = ref(initialTargetItems);
|
|
45
|
+
const sourceSelection = ref([]);
|
|
46
|
+
const targetSelection = ref([]);
|
|
47
|
+
const transferHeaderClass = computed(() => {
|
|
48
|
+
return props.context.transferHeaderClass || "text-base font-semibold";
|
|
49
|
+
});
|
|
50
|
+
const sourceItems = computed(() => {
|
|
51
|
+
const options = props.context?.options || [];
|
|
52
|
+
if (!Array.isArray(options)) return [];
|
|
53
|
+
return options.filter((item) => {
|
|
54
|
+
const itemValue = optionValueKey.value && typeof item === "object" ? item[optionValueKey.value] : item;
|
|
55
|
+
return !targetItems.value.some((t) => {
|
|
56
|
+
const targetValue = optionValueKey.value && typeof t === "object" ? t[optionValueKey.value] : t;
|
|
57
|
+
return targetValue === itemValue;
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
const dragSource = ref(null);
|
|
62
|
+
const draggedItems = ref([]);
|
|
63
|
+
const activeDropzone = ref(null);
|
|
64
|
+
const dragOverIndex = ref(null);
|
|
65
|
+
function getComparableValue(item) {
|
|
66
|
+
const valueKey = optionValueKey.value;
|
|
67
|
+
return valueKey && typeof item === "object" ? item?.[valueKey] : item;
|
|
68
|
+
}
|
|
69
|
+
function isSameOption(left, right) {
|
|
70
|
+
return getComparableValue(left) === getComparableValue(right);
|
|
71
|
+
}
|
|
72
|
+
function getUniqueItems(items) {
|
|
73
|
+
return items.filter((item, index) => items.findIndex((candidate) => isSameOption(candidate, item)) === index);
|
|
74
|
+
}
|
|
75
|
+
function mergeUniqueItems(base, toAdd) {
|
|
76
|
+
return [...base, ...toAdd.filter((item) => !base.some((candidate) => isSameOption(candidate, item)))];
|
|
77
|
+
}
|
|
78
|
+
function getDraggableItems(origin, option) {
|
|
79
|
+
const selection = origin === "source" ? sourceSelection.value : targetSelection.value;
|
|
80
|
+
if (!selection.length) return [option];
|
|
81
|
+
const hasOptionSelected = selection.some((item) => isSameOption(item, option));
|
|
82
|
+
return hasOptionSelected ? getUniqueItems(selection) : [option];
|
|
83
|
+
}
|
|
84
|
+
function clearDragState() {
|
|
85
|
+
dragSource.value = null;
|
|
86
|
+
draggedItems.value = [];
|
|
87
|
+
activeDropzone.value = null;
|
|
88
|
+
dragOverIndex.value = null;
|
|
89
|
+
}
|
|
90
|
+
function canDropInto(target) {
|
|
91
|
+
if (!transferDragDrop.value || props.context.disabled || !dragSource.value || draggedItems.value.length === 0) return false;
|
|
92
|
+
// The target list accepts cross-list moves as well as same-list reordering.
|
|
93
|
+
if (target === "target") return true;
|
|
94
|
+
// The source list only accepts items coming from the target (i.e. removal).
|
|
95
|
+
return dragSource.value !== target;
|
|
96
|
+
}
|
|
97
|
+
function handleOptionDragStart(origin, option, event) {
|
|
98
|
+
if (!transferDragDrop.value || props.context.disabled) return;
|
|
99
|
+
draggedItems.value = getDraggableItems(origin, option);
|
|
100
|
+
dragSource.value = origin;
|
|
101
|
+
if (event.dataTransfer) {
|
|
102
|
+
event.dataTransfer.effectAllowed = "move";
|
|
103
|
+
event.dataTransfer.setData("text/plain", "formkit-openvue-transfer");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function handleOptionDragEnd() {
|
|
107
|
+
clearDragState();
|
|
108
|
+
}
|
|
109
|
+
function handleDropzoneDragOver(target, event) {
|
|
110
|
+
if (!canDropInto(target)) return;
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
activeDropzone.value = target;
|
|
113
|
+
// Hovering empty space (not over a specific item) clears the per-item highlight.
|
|
114
|
+
dragOverIndex.value = null;
|
|
115
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
|
|
116
|
+
}
|
|
117
|
+
function handleDropzoneDragLeave(target) {
|
|
118
|
+
if (activeDropzone.value === target) activeDropzone.value = null;
|
|
119
|
+
}
|
|
120
|
+
function handleDropzoneDrop(target, event) {
|
|
121
|
+
if (!canDropInto(target)) {
|
|
122
|
+
clearDragState();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
if (target === "target") {
|
|
127
|
+
targetItems.value = mergeUniqueItems(targetItems.value, draggedItems.value);
|
|
128
|
+
sourceSelection.value = [];
|
|
129
|
+
} else {
|
|
130
|
+
targetItems.value = targetItems.value.filter((item) => !draggedItems.value.some((dragged) => isSameOption(dragged, item)));
|
|
131
|
+
targetSelection.value = [];
|
|
132
|
+
}
|
|
133
|
+
clearDragState();
|
|
134
|
+
}
|
|
135
|
+
function handleTargetItemDragOver(index, event) {
|
|
136
|
+
if (!canDropInto("target")) return;
|
|
137
|
+
// Handle the drop at the item level so it lands at a precise position.
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
event.stopPropagation();
|
|
140
|
+
activeDropzone.value = "target";
|
|
141
|
+
dragOverIndex.value = index;
|
|
142
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
|
|
143
|
+
}
|
|
144
|
+
function handleTargetItemDrop(index, event) {
|
|
145
|
+
if (!canDropInto("target")) {
|
|
146
|
+
clearDragState();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
event.stopPropagation();
|
|
151
|
+
const referenceItem = targetItems.value[index];
|
|
152
|
+
const itemsToInsert = getUniqueItems(draggedItems.value);
|
|
153
|
+
if (dragSource.value === "target") {
|
|
154
|
+
// Reorder within the target list: move the dragged items to the drop position.
|
|
155
|
+
if (itemsToInsert.some((dragged) => isSameOption(dragged, referenceItem))) {
|
|
156
|
+
clearDragState();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const remaining = targetItems.value.filter((item) => !itemsToInsert.some((dragged) => isSameOption(dragged, item)));
|
|
160
|
+
let insertAt = remaining.findIndex((item) => isSameOption(item, referenceItem));
|
|
161
|
+
if (insertAt === -1) insertAt = remaining.length;
|
|
162
|
+
remaining.splice(insertAt, 0, ...itemsToInsert);
|
|
163
|
+
targetItems.value = remaining;
|
|
164
|
+
targetSelection.value = [];
|
|
165
|
+
} else {
|
|
166
|
+
// Cross-list move: insert the dragged source items at the drop position.
|
|
167
|
+
const additions = itemsToInsert.filter((item) => !targetItems.value.some((candidate) => isSameOption(candidate, item)));
|
|
168
|
+
const updated = [...targetItems.value];
|
|
169
|
+
updated.splice(index, 0, ...additions);
|
|
170
|
+
targetItems.value = updated;
|
|
171
|
+
sourceSelection.value = [];
|
|
172
|
+
}
|
|
173
|
+
clearDragState();
|
|
174
|
+
}
|
|
175
|
+
function resolveOptionDisabled(option) {
|
|
176
|
+
const optionDisabled = props.context.optionDisabled;
|
|
177
|
+
if (!optionDisabled) return false;
|
|
178
|
+
if (typeof optionDisabled === "function") return !!optionDisabled(option);
|
|
179
|
+
if (typeof optionDisabled === "string") return !!option?.[optionDisabled];
|
|
180
|
+
return !!optionDisabled;
|
|
181
|
+
}
|
|
182
|
+
function resolveOptionLabel(option) {
|
|
183
|
+
if (!props.context.optionLabel) return String(option);
|
|
184
|
+
if (typeof props.context.optionLabel === "function") return String(props.context.optionLabel(option));
|
|
185
|
+
return String(option?.[props.context.optionLabel] ?? option);
|
|
186
|
+
}
|
|
187
|
+
function transferSelected() {
|
|
188
|
+
if (sourceSelection.value.length === 0) return;
|
|
189
|
+
// Use splice-based approach for better performance
|
|
190
|
+
targetItems.value = [...targetItems.value, ...sourceSelection.value];
|
|
191
|
+
sourceSelection.value = [];
|
|
192
|
+
}
|
|
193
|
+
function transferAll() {
|
|
194
|
+
if (sourceItems.value.length === 0) return;
|
|
195
|
+
targetItems.value = [...targetItems.value, ...sourceItems.value];
|
|
196
|
+
sourceSelection.value = [];
|
|
197
|
+
}
|
|
198
|
+
function removeSelected() {
|
|
199
|
+
if (targetSelection.value.length === 0) return;
|
|
200
|
+
// Filter out selected items using splice-inspired logic
|
|
201
|
+
const valueKey = optionValueKey.value;
|
|
202
|
+
targetItems.value = targetItems.value.filter((item) => {
|
|
203
|
+
const itemValue = valueKey && typeof item === "object" ? item[valueKey] : item;
|
|
204
|
+
return !targetSelection.value.some((sel) => {
|
|
205
|
+
const selValue = valueKey && typeof sel === "object" ? sel[valueKey] : sel;
|
|
206
|
+
return selValue === itemValue;
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
targetSelection.value = [];
|
|
210
|
+
}
|
|
211
|
+
function removeAll() {
|
|
212
|
+
if (targetItems.value.length === 0) return;
|
|
213
|
+
targetItems.value = [];
|
|
214
|
+
targetSelection.value = [];
|
|
215
|
+
}
|
|
216
|
+
watch(targetItems, (newVal) => {
|
|
217
|
+
modelValue.value = newVal;
|
|
218
|
+
handleInput(newVal);
|
|
219
|
+
handleChange(newVal);
|
|
220
|
+
}, { deep: true });
|
|
221
|
+
// Watch for external changes to modelValue and update targetItems
|
|
222
|
+
watch(() => modelValue.value, (newVal) => {
|
|
223
|
+
if (props.context.displayMode === "transfer" && Array.isArray(newVal)) {
|
|
224
|
+
const converted = valuesToObjects(newVal);
|
|
225
|
+
// Only update if the values are actually different to avoid infinite loops
|
|
226
|
+
if (JSON.stringify(converted) !== JSON.stringify(targetItems.value)) {
|
|
227
|
+
targetItems.value = converted;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}, { deep: true });
|
|
231
|
+
</script>
|
|
232
|
+
|
|
233
|
+
<template>
|
|
234
|
+
<!-- Single Mode (default) -->
|
|
235
|
+
<div v-if="!context.displayMode || context.displayMode === 'single'" class="p-formkit">
|
|
236
|
+
<Listbox
|
|
237
|
+
:id="context.id"
|
|
238
|
+
v-model="modelValue"
|
|
239
|
+
v-bind="context?.attrs"
|
|
240
|
+
:disabled="!!context?.disabled"
|
|
241
|
+
:readonly="context?.attrs.readonly ?? false"
|
|
242
|
+
:list-style="context?.attrs.style"
|
|
243
|
+
:class="context?.attrs?.class"
|
|
244
|
+
:invalid="isInvalid"
|
|
245
|
+
:tabindex="context?.attrs.tabindex"
|
|
246
|
+
:aria-label="context?.attrs.ariaLabel"
|
|
247
|
+
:aria-labelledby="context?.attrs.ariaLabelledby"
|
|
248
|
+
:options="context?.options"
|
|
249
|
+
:option-label="context.optionLabel"
|
|
250
|
+
:option-value="context.optionValue"
|
|
251
|
+
:option-disabled="context.optionDisabled"
|
|
252
|
+
:option-group-label="context.optionGroupLabel"
|
|
253
|
+
:option-group-children="context.optionGroupChildren"
|
|
254
|
+
:multiple="context.multiple ?? false"
|
|
255
|
+
:filter="context.filter ?? false"
|
|
256
|
+
:filter-icon="context.filterIcon"
|
|
257
|
+
:filter-placeholder="context.filterPlaceholder"
|
|
258
|
+
:filter-locale="context.filterLocale"
|
|
259
|
+
:filter-match-mode="context.filterMatchMode"
|
|
260
|
+
:auto-option-focus="context.autoOptionFocus ?? true"
|
|
261
|
+
:select-on-focus="context.selectOnFocus ?? false"
|
|
262
|
+
:data-key="context.dataKey"
|
|
263
|
+
:meta-key-selection="context.metaKeySelection ?? false"
|
|
264
|
+
:virtual-scroller-options="context.virtualScrollerOptions"
|
|
265
|
+
:pt="context.pt"
|
|
266
|
+
:pt-options="context.ptOptions"
|
|
267
|
+
:unstyled="unstyled"
|
|
268
|
+
@update:model-value="handleInput"
|
|
269
|
+
@change="handleChange"
|
|
270
|
+
@blur="handleBlur"
|
|
271
|
+
>
|
|
272
|
+
<template v-for="slotName in validSlotNames" :key="slotName" #[slotName]="slotProps">
|
|
273
|
+
<component :is="context?.slots[slotName]" v-bind="{ ...context, ...slotProps }" />
|
|
274
|
+
</template>
|
|
275
|
+
</Listbox>
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<!-- Transfer Mode -->
|
|
279
|
+
<div
|
|
280
|
+
v-if="context.displayMode === 'transfer'"
|
|
281
|
+
:class="transferContainerClass"
|
|
282
|
+
>
|
|
283
|
+
<!-- Source List -->
|
|
284
|
+
<div
|
|
285
|
+
:class="[transferListContainerClass, { 'p-formkit-transfer-dropzone-active': activeDropzone === 'source' }]"
|
|
286
|
+
@dragover="handleDropzoneDragOver('source', $event)"
|
|
287
|
+
@dragleave="handleDropzoneDragLeave('source')"
|
|
288
|
+
@drop="handleDropzoneDrop('source', $event)"
|
|
289
|
+
>
|
|
290
|
+
<span
|
|
291
|
+
v-if="context.transferLeftHeaderText"
|
|
292
|
+
:class="transferHeaderClass"
|
|
293
|
+
>{{ context.transferLeftHeaderText }}</span>
|
|
294
|
+
<Listbox
|
|
295
|
+
:id="`${context.id}-transfer-source`"
|
|
296
|
+
v-model="sourceSelection"
|
|
297
|
+
v-bind="context?.attrs"
|
|
298
|
+
:disabled="!!context?.disabled"
|
|
299
|
+
:readonly="context?.attrs.readonly ?? false"
|
|
300
|
+
:list-style="context?.attrs.style"
|
|
301
|
+
:class="context?.attrs?.class"
|
|
302
|
+
:invalid="isInvalid"
|
|
303
|
+
:tabindex="context?.attrs.tabindex"
|
|
304
|
+
:aria-label="context?.attrs.ariaLabel || 'Source list'"
|
|
305
|
+
:aria-labelledby="context?.attrs.ariaLabelledby"
|
|
306
|
+
:options="sourceItems"
|
|
307
|
+
:option-label="context.optionLabel"
|
|
308
|
+
:option-disabled="context.optionDisabled"
|
|
309
|
+
:option-group-label="context.optionGroupLabel"
|
|
310
|
+
:option-group-children="context.optionGroupChildren"
|
|
311
|
+
:data-key="context.dataKey"
|
|
312
|
+
:multiple="true"
|
|
313
|
+
:filter="context.filter ?? false"
|
|
314
|
+
:filter-icon="context.filterIcon"
|
|
315
|
+
:filter-placeholder="context.filterPlaceholder"
|
|
316
|
+
:filter-locale="context.filterLocale"
|
|
317
|
+
:filter-match-mode="context.filterMatchMode"
|
|
318
|
+
:auto-option-focus="context.autoOptionFocus ?? true"
|
|
319
|
+
:select-on-focus="context.selectOnFocus ?? false"
|
|
320
|
+
:meta-key-selection="context.metaKeySelection ?? false"
|
|
321
|
+
:virtual-scroller-options="context.virtualScrollerOptions"
|
|
322
|
+
:pt="context.pt"
|
|
323
|
+
:pt-options="context.ptOptions"
|
|
324
|
+
:unstyled="unstyled"
|
|
325
|
+
@blur="handleBlur"
|
|
326
|
+
>
|
|
327
|
+
<template #option="slotProps">
|
|
328
|
+
<div
|
|
329
|
+
:draggable="transferDragDrop && !context.disabled && !resolveOptionDisabled(slotProps.option)"
|
|
330
|
+
class="p-formkit-transfer-option"
|
|
331
|
+
:class="{ 'p-formkit-transfer-option-draggable': transferDragDrop && !context.disabled && !resolveOptionDisabled(slotProps.option) }"
|
|
332
|
+
@dragstart="handleOptionDragStart('source', slotProps.option, $event)"
|
|
333
|
+
@dragend="handleOptionDragEnd"
|
|
334
|
+
>
|
|
335
|
+
<component
|
|
336
|
+
:is="context?.slots.option"
|
|
337
|
+
v-if="context?.slots?.option"
|
|
338
|
+
v-bind="{ ...context, ...slotProps }"
|
|
339
|
+
/>
|
|
340
|
+
<span v-else>{{ resolveOptionLabel(slotProps.option) }}</span>
|
|
341
|
+
</div>
|
|
342
|
+
</template>
|
|
343
|
+
<template v-for="slotName in transferSlotNames" :key="slotName" #[slotName]="slotProps">
|
|
344
|
+
<component :is="context?.slots[slotName]" v-bind="{ ...context, ...slotProps }" />
|
|
345
|
+
</template>
|
|
346
|
+
</Listbox>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<!-- Transfer Buttons -->
|
|
350
|
+
<div class="p-formkit-transfer-buttons">
|
|
351
|
+
<Button
|
|
352
|
+
icon="oi oi-angle-right"
|
|
353
|
+
:severity="transferButtonSeverity"
|
|
354
|
+
:class="transferButtonClass"
|
|
355
|
+
outlined
|
|
356
|
+
:disabled="sourceSelection.length === 0"
|
|
357
|
+
:aria-label="context.transferAll ? 'Move selected to target' : 'Move to target'"
|
|
358
|
+
@click="transferSelected"
|
|
359
|
+
/>
|
|
360
|
+
<Button
|
|
361
|
+
v-if="context.transferAll"
|
|
362
|
+
icon="oi oi-angle-double-right"
|
|
363
|
+
:severity="transferButtonSeverity"
|
|
364
|
+
:class="transferButtonClass"
|
|
365
|
+
outlined
|
|
366
|
+
:disabled="sourceItems.length === 0"
|
|
367
|
+
aria-label="Move all to target"
|
|
368
|
+
@click="transferAll"
|
|
369
|
+
/>
|
|
370
|
+
<Button
|
|
371
|
+
icon="oi oi-angle-left"
|
|
372
|
+
:severity="transferButtonSeverity"
|
|
373
|
+
:class="transferButtonClass"
|
|
374
|
+
outlined
|
|
375
|
+
:disabled="targetSelection.length === 0"
|
|
376
|
+
:aria-label="context.transferAll ? 'Move selected to source' : 'Move to source'"
|
|
377
|
+
@click="removeSelected"
|
|
378
|
+
/>
|
|
379
|
+
<Button
|
|
380
|
+
v-if="context.transferAll"
|
|
381
|
+
icon="oi oi-angle-double-left"
|
|
382
|
+
:severity="transferButtonSeverity"
|
|
383
|
+
:class="transferButtonClass"
|
|
384
|
+
outlined
|
|
385
|
+
:disabled="targetItems.length === 0"
|
|
386
|
+
aria-label="Move all to source"
|
|
387
|
+
@click="removeAll"
|
|
388
|
+
/>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
<!-- Target List -->
|
|
392
|
+
<div
|
|
393
|
+
:class="[transferListContainerClass, { 'p-formkit-transfer-dropzone-active': activeDropzone === 'target' }]"
|
|
394
|
+
@dragover="handleDropzoneDragOver('target', $event)"
|
|
395
|
+
@dragleave="handleDropzoneDragLeave('target')"
|
|
396
|
+
@drop="handleDropzoneDrop('target', $event)"
|
|
397
|
+
>
|
|
398
|
+
<span
|
|
399
|
+
v-if="context.transferRightHeaderText"
|
|
400
|
+
:class="transferHeaderClass"
|
|
401
|
+
>{{ context.transferRightHeaderText }}</span>
|
|
402
|
+
<Listbox
|
|
403
|
+
:id="`${context.id}-transfer-target`"
|
|
404
|
+
v-model="targetSelection"
|
|
405
|
+
v-bind="context?.attrs"
|
|
406
|
+
:disabled="!!context?.disabled"
|
|
407
|
+
:readonly="context?.attrs.readonly ?? false"
|
|
408
|
+
:list-style="context?.attrs.style"
|
|
409
|
+
:class="context?.attrs?.class"
|
|
410
|
+
:invalid="isInvalid"
|
|
411
|
+
:tabindex="context?.attrs.tabindex"
|
|
412
|
+
:aria-label="context?.attrs.ariaLabel || 'Target list'"
|
|
413
|
+
:aria-labelledby="context?.attrs.ariaLabelledby"
|
|
414
|
+
:options="targetItems"
|
|
415
|
+
:option-label="context.optionLabel"
|
|
416
|
+
:option-disabled="context.optionDisabled"
|
|
417
|
+
:option-group-label="context.optionGroupLabel"
|
|
418
|
+
:option-group-children="context.optionGroupChildren"
|
|
419
|
+
:data-key="context.dataKey"
|
|
420
|
+
:multiple="true"
|
|
421
|
+
:filter="context.filter ?? false"
|
|
422
|
+
:filter-icon="context.filterIcon"
|
|
423
|
+
:filter-placeholder="context.filterPlaceholder"
|
|
424
|
+
:filter-locale="context.filterLocale"
|
|
425
|
+
:filter-match-mode="context.filterMatchMode"
|
|
426
|
+
:auto-option-focus="context.autoOptionFocus ?? true"
|
|
427
|
+
:select-on-focus="context.selectOnFocus ?? false"
|
|
428
|
+
:meta-key-selection="context.metaKeySelection ?? false"
|
|
429
|
+
:virtual-scroller-options="context.virtualScrollerOptions"
|
|
430
|
+
:pt="context.pt"
|
|
431
|
+
:pt-options="context.ptOptions"
|
|
432
|
+
:unstyled="unstyled"
|
|
433
|
+
@blur="handleBlur"
|
|
434
|
+
>
|
|
435
|
+
<template #option="slotProps">
|
|
436
|
+
<div
|
|
437
|
+
:draggable="transferDragDrop && !context.disabled && !resolveOptionDisabled(slotProps.option)"
|
|
438
|
+
class="p-formkit-transfer-option"
|
|
439
|
+
:class="{
|
|
440
|
+
'p-formkit-transfer-option-draggable': transferDragDrop && !context.disabled && !resolveOptionDisabled(slotProps.option),
|
|
441
|
+
'p-formkit-transfer-option-dragover': dragOverIndex === slotProps.index,
|
|
442
|
+
}"
|
|
443
|
+
@dragstart="handleOptionDragStart('target', slotProps.option, $event)"
|
|
444
|
+
@dragend="handleOptionDragEnd"
|
|
445
|
+
@dragover="handleTargetItemDragOver(slotProps.index, $event)"
|
|
446
|
+
@drop="handleTargetItemDrop(slotProps.index, $event)"
|
|
447
|
+
>
|
|
448
|
+
<component
|
|
449
|
+
:is="context?.slots.option"
|
|
450
|
+
v-if="context?.slots?.option"
|
|
451
|
+
v-bind="{ ...context, ...slotProps }"
|
|
452
|
+
/>
|
|
453
|
+
<span v-else>{{ resolveOptionLabel(slotProps.option) }}</span>
|
|
454
|
+
</div>
|
|
455
|
+
</template>
|
|
456
|
+
<template v-for="slotName in transferSlotNames" :key="slotName" #[slotName]="slotProps">
|
|
457
|
+
<component :is="context?.slots[slotName]" v-bind="{ ...context, ...slotProps }" />
|
|
458
|
+
</template>
|
|
459
|
+
</Listbox>
|
|
460
|
+
</div>
|
|
461
|
+
</div>
|
|
462
|
+
</template>
|
|
463
|
+
|
|
464
|
+
<style scoped>
|
|
465
|
+
.p-formkit-transfer :deep(.p-listbox) {
|
|
466
|
+
width: 100%;
|
|
467
|
+
height: 100%;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.p-formkit-transfer :deep(.p-listbox-list-container) {
|
|
471
|
+
max-height: none;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.p-formkit-transfer-dropzone-active :deep(.p-listbox) {
|
|
475
|
+
outline: 2px dashed var(--p-primary-color);
|
|
476
|
+
outline-offset: 2px;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.p-formkit-transfer-option-dragover {
|
|
480
|
+
box-shadow: inset 0 2px 0 0 var(--p-primary-color);
|
|
481
|
+
}
|
|
482
|
+
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useFormKitInput } from "../composables";
|
|
3
|
+
const props = defineProps({ context: {
|
|
4
|
+
type: Object,
|
|
5
|
+
required: true
|
|
6
|
+
} });
|
|
7
|
+
const { validSlotNames, unstyled, isInvalid, handleBlur, handleChange, modelValue } = useFormKitInput(props.context);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div class="p-formkit">
|
|
12
|
+
<MultiSelect
|
|
13
|
+
v-model="modelValue"
|
|
14
|
+
v-bind="context?.attrs"
|
|
15
|
+
:input-id="context.id"
|
|
16
|
+
:disabled="!!context?.disabled"
|
|
17
|
+
:readonly="context?.attrs.readonly ?? false"
|
|
18
|
+
:list-style="context?.attrs.style"
|
|
19
|
+
:class="context?.attrs?.class"
|
|
20
|
+
:invalid="isInvalid"
|
|
21
|
+
:tabindex="context?.attrs.tabindex"
|
|
22
|
+
:aria-label="context?.attrs.ariaLabel"
|
|
23
|
+
:aria-labelledby="context?.attrs.ariaLabelledby"
|
|
24
|
+
:size="context?.size ?? undefined"
|
|
25
|
+
:placeholder="context.placeholder"
|
|
26
|
+
:options="context.options"
|
|
27
|
+
:option-label="context.optionLabel"
|
|
28
|
+
:option-value="context.optionValue"
|
|
29
|
+
:option-disabled="context.optionDisabled"
|
|
30
|
+
:option-group-label="context.optionGroupLabel"
|
|
31
|
+
:option-group-children="context.optionGroupChildren"
|
|
32
|
+
:scroll-height="context.scrollHeight"
|
|
33
|
+
:data-key="context.dataKey"
|
|
34
|
+
:filter="context.filter ?? false"
|
|
35
|
+
:filter-placeholder="context.filterPlaceholder"
|
|
36
|
+
:filter-locale="context.filterLocale"
|
|
37
|
+
:filter-match-mode="context.filterMatchMode"
|
|
38
|
+
:fitler-fields="context.filterFields"
|
|
39
|
+
:append-to="context.appendTo"
|
|
40
|
+
:close-icon="context.closeIcon"
|
|
41
|
+
:display="context.display"
|
|
42
|
+
:max-selected-labels="context.maxSelectedLabels"
|
|
43
|
+
:selected-items-label="context.selectedItemsLabel"
|
|
44
|
+
:selection-limit="context.selectionLimit"
|
|
45
|
+
:show-toggle-all="context.showToggleAll"
|
|
46
|
+
:loading="context.loading"
|
|
47
|
+
:select-all="context.selectAll"
|
|
48
|
+
:reset-filter-on-hide="context.resetFilterOnHide"
|
|
49
|
+
:virtual-scroller-options="context.virtualScrollerOptions"
|
|
50
|
+
:auto-option-focus="context.autoOptionFocus"
|
|
51
|
+
:auto-filter-focus="context.autoFilterFocus"
|
|
52
|
+
:filter-message="context.filterMessage"
|
|
53
|
+
:selection-message="context.selectionMessage"
|
|
54
|
+
:empty-selection-message="context.emptySelectionMessage"
|
|
55
|
+
:empty-filter-message="context.emptyFilterMessage"
|
|
56
|
+
:empty-message="context.emptyMessage"
|
|
57
|
+
:pt="context.pt"
|
|
58
|
+
:pt-options="context.ptOptions"
|
|
59
|
+
:unstyled="unstyled"
|
|
60
|
+
@change="handleChange"
|
|
61
|
+
@blur="handleBlur"
|
|
62
|
+
>
|
|
63
|
+
<template v-for="slotName in validSlotNames" :key="slotName" #[slotName]="slotProps">
|
|
64
|
+
<component :is="context?.slots[slotName]" v-bind="{ ...context, ...slotProps }" />
|
|
65
|
+
</template>
|
|
66
|
+
</MultiSelect>
|
|
67
|
+
</div>
|
|
68
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useI18n } from "vue-i18n";
|
|
4
|
+
import { useFormKitSection } from "../composables";
|
|
5
|
+
import FormKitIcon from "./FormKitIcon.vue";
|
|
6
|
+
import FormKitPrefix from "./FormKitPrefix.vue";
|
|
7
|
+
import FormKitSuffix from "./FormKitSuffix.vue";
|
|
8
|
+
const props = defineProps({ context: {
|
|
9
|
+
type: Object,
|
|
10
|
+
required: true
|
|
11
|
+
} });
|
|
12
|
+
const { hasPrefix, hasPrefixIcon, hasSuffix, hasSuffixIcon } = useFormKitSection(props.context);
|
|
13
|
+
const { t } = useI18n();
|
|
14
|
+
const translated = computed(() => {
|
|
15
|
+
if (props.context?._value) return props.context?.trueValue ?? t("formkit.form.true", "true");
|
|
16
|
+
else return props.context?.falseValue ?? t("formkit.form.false", "false");
|
|
17
|
+
});
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div class="p-formkit p-output-boolean">
|
|
22
|
+
<FormKitIcon v-if="hasPrefixIcon" :icon-class="context?.iconPrefix" :on-click="context?.onIconPrefixClicked" :tooltip="context?.iconPrefixTooltip" position="prefix" />
|
|
23
|
+
<FormKitPrefix v-if="hasPrefix" :prefix="context?.prefix" />
|
|
24
|
+
<span :id="context?.id" :style="context?.attrs?.style" :class="context?.attrs?.class">
|
|
25
|
+
{{ translated }}
|
|
26
|
+
</span>
|
|
27
|
+
<FormKitSuffix v-if="hasSuffix" :suffix="context?.suffix" />
|
|
28
|
+
<FormKitIcon v-if="hasSuffixIcon" :icon-class="context?.iconSuffix" :on-click="context?.onIconSuffixClicked" :tooltip="context?.iconSuffixTooltip" position="suffix" />
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useI18n } from "vue-i18n";
|
|
4
|
+
import { useFormKitSection } from "../composables";
|
|
5
|
+
import FormKitIcon from "./FormKitIcon.vue";
|
|
6
|
+
import FormKitPrefix from "./FormKitPrefix.vue";
|
|
7
|
+
import FormKitSuffix from "./FormKitSuffix.vue";
|
|
8
|
+
const props = defineProps({ context: {
|
|
9
|
+
type: Object,
|
|
10
|
+
required: true
|
|
11
|
+
} });
|
|
12
|
+
const { hasPrefix, hasPrefixIcon, hasSuffix, hasSuffixIcon } = useFormKitSection(props.context);
|
|
13
|
+
const { d } = useI18n();
|
|
14
|
+
const converted = computed(() => {
|
|
15
|
+
if (props?.context?._value) {
|
|
16
|
+
let result = "";
|
|
17
|
+
const format = props?.context?.attrs?.value?.format ? props?.context?.attrs.value.format : "short";
|
|
18
|
+
try {
|
|
19
|
+
result = d(props?.context?._value, format);
|
|
20
|
+
}
|
|
21
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
22
|
+
catch (e) {}
|
|
23
|
+
return result;
|
|
24
|
+
} else {
|
|
25
|
+
return "";
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<div class="p-formkit p-output-date">
|
|
32
|
+
<FormKitIcon v-if="hasPrefixIcon" :icon-class="context?.iconPrefix" :on-click="context?.onIconPrefixClicked" :tooltip="context?.iconPrefixTooltip" position="prefix" />
|
|
33
|
+
<FormKitPrefix v-if="hasPrefix" :prefix="context?.prefix" />
|
|
34
|
+
<span :id="context?.id" :style="context?.attrs?.style" :class="context?.attrs?.class">
|
|
35
|
+
{{ converted }}
|
|
36
|
+
</span>
|
|
37
|
+
<FormKitSuffix v-if="hasSuffix" :suffix="context?.suffix" />
|
|
38
|
+
<FormKitIcon v-if="hasSuffixIcon" :icon-class="context?.iconSuffix" :on-click="context?.onIconSuffixClicked" :tooltip="context?.iconSuffixTooltip" position="suffix" />
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useFormKitSection, useOutputDuration } from "../composables";
|
|
3
|
+
import FormKitIcon from "./FormKitIcon.vue";
|
|
4
|
+
import FormKitPrefix from "./FormKitPrefix.vue";
|
|
5
|
+
import FormKitSuffix from "./FormKitSuffix.vue";
|
|
6
|
+
const props = defineProps({ context: {
|
|
7
|
+
type: Object,
|
|
8
|
+
required: true
|
|
9
|
+
} });
|
|
10
|
+
const { hasPrefix, hasPrefixIcon, hasSuffix, hasSuffixIcon } = useFormKitSection(props.context);
|
|
11
|
+
const { formattedDuration } = useOutputDuration();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div class="p-formkit p-output-duration">
|
|
16
|
+
<FormKitIcon v-if="hasPrefixIcon" :icon-class="context?.iconPrefix" :on-click="context?.onIconPrefixClicked" :tooltip="context?.iconPrefixTooltip" position="prefix" />
|
|
17
|
+
<FormKitPrefix v-if="hasPrefix" :prefix="context?.prefix" />
|
|
18
|
+
<span :id="context?.id" :style="context?.attrs?.style" :class="context?.attrs?.class">
|
|
19
|
+
{{ formattedDuration(context?._value) }}
|
|
20
|
+
</span>
|
|
21
|
+
<FormKitSuffix v-if="hasSuffix" :suffix="context?.suffix" />
|
|
22
|
+
<FormKitIcon v-if="hasSuffixIcon" :icon-class="context?.iconSuffix" :on-click="context?.onIconSuffixClicked" :tooltip="context?.iconSuffixTooltip" position="suffix" />
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|