889212d643
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>
105 lines
2.1 KiB
TypeScript
105 lines
2.1 KiB
TypeScript
/**
|
|
* useKbxDirtyState — v60
|
|
* Track unsaved changes in forms
|
|
*/
|
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
export interface DirtyState {
|
|
[key: string]: boolean
|
|
}
|
|
|
|
export function useKbxDirtyState(initialState: DirtyState = {}) {
|
|
const dirtyFields = ref<DirtyState>(initialState)
|
|
|
|
/**
|
|
* Check if form is dirty (has unsaved changes)
|
|
*/
|
|
const dirty = computed(() => Object.values(dirtyFields.value).some(v => v))
|
|
|
|
/**
|
|
* Check if specific field is dirty
|
|
*/
|
|
const isFieldDirty = (field: string): boolean => {
|
|
return dirtyFields.value[field] ?? false
|
|
}
|
|
|
|
/**
|
|
* Mark field as dirty
|
|
*/
|
|
const markFieldDirty = (field: string): void => {
|
|
dirtyFields.value[field] = true
|
|
}
|
|
|
|
/**
|
|
* Mark field as clean
|
|
*/
|
|
const markFieldClean = (field: string): void => {
|
|
dirtyFields.value[field] = false
|
|
}
|
|
|
|
/**
|
|
* Mark all fields as clean
|
|
*/
|
|
const markAllClean = (): void => {
|
|
Object.keys(dirtyFields.value).forEach(key => {
|
|
dirtyFields.value[key] = false
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Mark all fields as dirty
|
|
*/
|
|
const markAllDirty = (): void => {
|
|
Object.keys(dirtyFields.value).forEach(key => {
|
|
dirtyFields.value[key] = true
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Reset to initial state
|
|
*/
|
|
const reset = (newInitialState: DirtyState = {}): void => {
|
|
dirtyFields.value = newInitialState
|
|
}
|
|
|
|
/**
|
|
* Touch field (mark as visited)
|
|
*/
|
|
const touchField = (field: string): void => {
|
|
if (!(field in dirtyFields.value)) {
|
|
dirtyFields.value[field] = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get dirty field names
|
|
*/
|
|
const getDirtyFields = (): string[] => {
|
|
return Object.entries(dirtyFields.value)
|
|
.filter(([, isDirty]) => isDirty)
|
|
.map(([field]) => field)
|
|
}
|
|
|
|
/**
|
|
* Set dirty state of multiple fields
|
|
*/
|
|
const setDirtyFields = (fields: DirtyState): void => {
|
|
dirtyFields.value = { ...dirtyFields.value, ...fields }
|
|
}
|
|
|
|
return {
|
|
dirty,
|
|
dirtyFields,
|
|
isFieldDirty,
|
|
markFieldDirty,
|
|
markFieldClean,
|
|
markAllClean,
|
|
markAllDirty,
|
|
touchField,
|
|
getDirtyFields,
|
|
setDirtyFields,
|
|
reset,
|
|
}
|
|
}
|