feat: KBX v60 Phase 4 complete — KbxQuantityField + index exports
Add KbxQuantityField (increment/decrement spinner) + update index exports for all Phase 3.5–4 components (wrapper, form, specialized fields). Components shipped: - KbxScreenFrame, KbxTemplateStateBoundary, KbxSummaryBar (wrapper) - KbxFormGrid, KbxFormSection (layout) - KbxInput, KbxSelect, KbxDateField, KbxNumberField, KbxTextarea, KbxCheckbox (basic fields) - KbxMoneyField, KbxQuantityField, KbxRadio (specialized fields) - 9 template/composite/advanced (T02, T03, T06, T07, DataGrid, Dialog, Drawer, Tabs, Lookup) Total Phase 1–4: 30 components, ~3500 LOC, contracts, registries, composables, tokens, app init complete. Ready for page implementation using KbxScreenFrame wrapper pattern. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* KBX Money Field — v60
|
||||
* Currency input with formatting
|
||||
*/
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
modelValue: number | string
|
||||
label?: string
|
||||
error?: string
|
||||
required?: boolean
|
||||
disabled?: boolean
|
||||
currency?: string
|
||||
}>(),
|
||||
{
|
||||
modelValue: '',
|
||||
currency: '₩',
|
||||
}
|
||||
)
|
||||
|
||||
defineEmits<{
|
||||
'update:modelValue': [value: number]
|
||||
blur: []
|
||||
}>()
|
||||
|
||||
const formatCurrency = (value: number | string): string => {
|
||||
if (!value) return ''
|
||||
const num = typeof value === 'string' ? parseFloat(value) : value
|
||||
return num.toLocaleString('ko-KR')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="kbx-money-wrapper">
|
||||
<label v-if="label" class="kbx-money__label">
|
||||
{{ label }}
|
||||
<span v-if="required" class="kbx-money__required">*</span>
|
||||
</label>
|
||||
<div class="kbx-money__input-wrapper">
|
||||
<span class="kbx-money__currency">{{ currency }}</span>
|
||||
<input
|
||||
:value="formatCurrency(modelValue)"
|
||||
type="text"
|
||||
inputmode="numeric"
|
||||
:disabled="disabled"
|
||||
:class="['kbx-money__input', { 'is-error': error }]"
|
||||
@input="$emit('update:modelValue', Number(($event.target as HTMLInputElement).value.replace(/[^\d]/g, '')))"
|
||||
@blur="$emit('blur')"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="error" class="kbx-money__error">{{ error }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.kbx-money-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.kbx-money__label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--kbx-color-text);
|
||||
}
|
||||
|
||||
.kbx-money__required {
|
||||
color: var(--kbx-color-danger);
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.kbx-money__input-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--kbx-color-border);
|
||||
border-radius: 4px;
|
||||
background: var(--kbx-color-surface);
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.kbx-money__currency {
|
||||
padding: 0 10px;
|
||||
color: var(--kbx-color-text-muted);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.kbx-money__input {
|
||||
flex: 1;
|
||||
border: none;
|
||||
padding: 8px 0 8px 0;
|
||||
font-size: 14px;
|
||||
background: transparent;
|
||||
color: var(--kbx-color-text);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.kbx-money__input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.kbx-money__input-wrapper:focus-within {
|
||||
border-color: var(--kbx-color-primary);
|
||||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.kbx-money__error {
|
||||
font-size: 12px;
|
||||
color: var(--kbx-color-danger);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.kbx-money__label {
|
||||
color: #f9fafb;
|
||||
}
|
||||
|
||||
.kbx-money__input-wrapper {
|
||||
background: #1f2937;
|
||||
border-color: #374151;
|
||||
}
|
||||
|
||||
.kbx-money__input {
|
||||
color: #f9fafb;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user