refactor(frontend): implement Full Transparent Wrapper Pattern with v-bind=\ and \ passthrough to expose 100% PrimeVue native capabilities without feature loss
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 10s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 19s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 9s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 9s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 10s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 19s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 9s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 9s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
<!-- PrimeVue Select Adapter Wrapper: QuantComboBox -->
|
||||
<!-- PrimeVue Select Adapter Wrapper: QuantComboBox (Full Transparent Passthrough Wrapper) -->
|
||||
<template>
|
||||
<div class="quant-combobox-wrapper w-full">
|
||||
<div class="quant-combobox-wrapper flex flex-col gap-1 w-full">
|
||||
<label v-if="label" class="text-xs font-bold text-slate-800">
|
||||
{{ label }} <span v-if="required" class="text-rose-600">*</span>
|
||||
</label>
|
||||
<Select
|
||||
v-bind="$attrs"
|
||||
:id="id"
|
||||
:modelValue="modelValue"
|
||||
:options="formattedOptions"
|
||||
@@ -9,9 +13,17 @@
|
||||
optionValue="value"
|
||||
:placeholder="placeholder || '선택하세요'"
|
||||
:disabled="disabled"
|
||||
:showClear="showClear !== false"
|
||||
:filter="filter !== false"
|
||||
filterPlaceholder="검색어 입력..."
|
||||
class="w-full h-9 border border-slate-300 rounded text-xs text-slate-900 font-medium bg-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
@update:modelValue="onSelectChange"
|
||||
/>
|
||||
>
|
||||
<!-- PrimeVue Select 슬롯 100% 투명 전파 -->
|
||||
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
|
||||
<slot :name="slotName" v-bind="slotProps || {}"></slot>
|
||||
</template>
|
||||
</Select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -19,12 +31,20 @@
|
||||
import { computed } from 'vue';
|
||||
import Select from 'primevue/select';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
id?: string;
|
||||
label?: string;
|
||||
modelValue?: string | number;
|
||||
options: Array<string | { label: string; value: string | number }>;
|
||||
placeholder?: string;
|
||||
required?: boolean;
|
||||
disabled?: boolean;
|
||||
showClear?: boolean;
|
||||
filter?: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
<!-- PrimeVue DataTable Adapter Wrapper: QuantDataGrid -->
|
||||
<!-- PrimeVue DataTable Adapter Wrapper: QuantDataGrid (Full Transparent Passthrough Wrapper) -->
|
||||
<template>
|
||||
<div class="quant-datagrid-wrapper w-full overflow-hidden border border-slate-300 rounded-lg shadow-2xs bg-white">
|
||||
<DataTable
|
||||
v-bind="$attrs"
|
||||
:value="items"
|
||||
:loading="loading"
|
||||
:paginator="paginator"
|
||||
:paginator="paginator !== false"
|
||||
:rows="rows || 10"
|
||||
:rowsPerPageOptions="[10, 25, 50, 100]"
|
||||
dataKey="id"
|
||||
responsiveLayout="scroll"
|
||||
resizableColumns
|
||||
columnResizeMode="fit"
|
||||
class="p-datatable-sm w-full text-xs"
|
||||
tableStyle="min-width: 50rem"
|
||||
>
|
||||
@@ -18,6 +21,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 사용자 정의 슬롯 100% 전파 -->
|
||||
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
|
||||
<slot :name="slotName" v-bind="slotProps || {}"></slot>
|
||||
</template>
|
||||
|
||||
<Column
|
||||
v-for="col in headers"
|
||||
:key="col.key"
|
||||
@@ -42,6 +50,10 @@
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
});
|
||||
|
||||
export interface GridColumn {
|
||||
key: string;
|
||||
label: string;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<!-- PrimeVue InputText Adapter Wrapper: QuantInput (Strict Numeric Filter Support) -->
|
||||
<!-- PrimeVue InputText Adapter Wrapper: QuantInput (Full Transparent Passthrough Wrapper) -->
|
||||
<template>
|
||||
<div class="quant-input-wrapper flex flex-col gap-1 w-full">
|
||||
<label v-if="label" class="text-xs font-bold text-slate-800">
|
||||
{{ label }} <span v-if="required" class="text-rose-600">*</span>
|
||||
</label>
|
||||
<InputText
|
||||
v-bind="$attrs"
|
||||
:id="id"
|
||||
:type="inputType"
|
||||
:modelValue="displayValue"
|
||||
@@ -15,7 +16,12 @@
|
||||
@keydown="onKeyDown"
|
||||
@paste="onPaste"
|
||||
@update:modelValue="onInput"
|
||||
/>
|
||||
>
|
||||
<!-- PrimeVue 원본 슬롯 100% 투명 전파 -->
|
||||
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
|
||||
<slot :name="slotName" v-bind="slotProps || {}"></slot>
|
||||
</template>
|
||||
</InputText>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -23,6 +29,10 @@
|
||||
import { computed } from 'vue';
|
||||
import InputText from 'primevue/inputtext';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
id?: string;
|
||||
label?: string;
|
||||
@@ -37,7 +47,6 @@ const props = defineProps<{
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
const isNumeric = computed(() => props.type === 'number');
|
||||
|
||||
const inputType = computed(() => (isNumeric.value ? 'text' : props.type || 'text'));
|
||||
|
||||
const displayValue = computed(() => {
|
||||
@@ -47,37 +56,27 @@ const displayValue = computed(() => {
|
||||
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
if (!isNumeric.value) return;
|
||||
|
||||
const allowedKeys = [
|
||||
'Backspace', 'Delete', 'Tab', 'Escape', 'Enter',
|
||||
'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown',
|
||||
'Home', 'End', '.', '-'
|
||||
];
|
||||
|
||||
if (allowedKeys.includes(e.key) || e.ctrlKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/^[0-9]$/.test(e.key)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (allowedKeys.includes(e.key) || e.ctrlKey || e.metaKey) return;
|
||||
if (!/^[0-9]$/.test(e.key)) e.preventDefault();
|
||||
};
|
||||
|
||||
const onPaste = (e: ClipboardEvent) => {
|
||||
if (!isNumeric.value) return;
|
||||
|
||||
const pasteData = e.clipboardData?.getData('text') || '';
|
||||
if (/[^0-9.-]/g.test(pasteData)) {
|
||||
e.preventDefault();
|
||||
const sanitized = pasteData.replace(/[^0-9.-]/g, '');
|
||||
onInput(sanitized);
|
||||
onInput(pasteData.replace(/[^0-9.-]/g, ''));
|
||||
}
|
||||
};
|
||||
|
||||
const onInput = (val: string | undefined) => {
|
||||
let finalVal = val ?? '';
|
||||
if (isNumeric.value) {
|
||||
// 숫자가 아닌 모든 문자 원천 정제
|
||||
finalVal = finalVal.replace(/[^0-9.-]/g, '');
|
||||
}
|
||||
emit('update:modelValue', finalVal);
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<!-- PrimeVue DataTable Adapter Wrapper: QuantMasterGrid -->
|
||||
<!-- PrimeVue DataTable Adapter Wrapper: QuantMasterGrid (Full Transparent Passthrough Wrapper) -->
|
||||
<template>
|
||||
<div class="quant-master-grid-wrapper w-full overflow-hidden border border-slate-300 rounded shadow-2xs bg-white">
|
||||
<DataTable
|
||||
v-bind="$attrs"
|
||||
:value="items || []"
|
||||
dataKey="id"
|
||||
responsiveLayout="scroll"
|
||||
resizableColumns
|
||||
columnResizeMode="fit"
|
||||
class="p-datatable-sm w-full text-xs"
|
||||
:style="{ maxHeight: height ? height + 'px' : '300px' }"
|
||||
>
|
||||
@@ -14,12 +17,18 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 사용자 정의 슬롯 100% 전파 -->
|
||||
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
|
||||
<slot :name="slotName" v-bind="slotProps || {}"></slot>
|
||||
</template>
|
||||
|
||||
<Column
|
||||
v-for="col in gridHeaders"
|
||||
:key="col.key"
|
||||
:field="col.key"
|
||||
:header="col.label"
|
||||
:style="{ width: col.width || 'auto', textAlign: col.align || 'left' }"
|
||||
sortable
|
||||
>
|
||||
<template #body="slotProps">
|
||||
<slot :name="col.key" :item="slotProps.data" :value="slotProps.data[col.key]">
|
||||
@@ -38,6 +47,10 @@ import { computed } from 'vue';
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
});
|
||||
|
||||
export interface GridHeader {
|
||||
key: string;
|
||||
label: string;
|
||||
@@ -53,7 +66,6 @@ const props = defineProps<{
|
||||
|
||||
const gridHeaders = computed(() => {
|
||||
if (props.headers && props.headers.length > 0) return props.headers;
|
||||
// Fallback defaults if not supplied
|
||||
return [
|
||||
{ key: 'code', label: '코드', width: '120px' },
|
||||
{ key: 'name', label: '명칭' },
|
||||
|
||||
Reference in New Issue
Block a user