UNPKG

@dynamicforms/vuetify-modal-form-kit

Version:
1 lines 84.3 kB
{"version":3,"file":"dynamicforms-vuetify-modal-form-kit.umd.cjs","sources":["../src/modal/dialog-size.ts","../src/modal/top-modal-tracker.ts","../src/modal/api.ts","../node_modules/vuetify/lib/util/helpers.js","../node_modules/vuetify/lib/util/getCurrentInstance.js","../node_modules/vuetify/lib/composables/display.js","../src/modal/df-modal.component.vue","../src/modal/df-api.component.vue","../src/core/form-layout/types.ts","../src/core/form-layout/component/component.ts","../src/core/form-layout/component/vuetify-component-builder.ts","../src/core/form-layout/column.ts","../src/core/form-layout/row.ts","../src/core/form-layout/form-builder.ts","../src/layout/component-render.vue","../src/layout/form-render.vue","../src/index.ts"],"sourcesContent":["enum DialogSize {\n SMALL = 1,\n MEDIUM = 2,\n LARGE = 3,\n X_LARGE = 4,\n DEFAULT = 0,\n}\n\nexport const defaultDialogSize: DialogSize = DialogSize.DEFAULT;\n\nnamespace DialogSize {\n const largeIdentifiers: string[] = ['large', 'lg', 'modal-lg'];\n const mediumIdentifiers: string[] = ['medium', 'md', 'modal-md'];\n const smallIdentifiers: string[] = ['small', 'sm', 'modal-sm'];\n const xLargeIdentifiers: string[] = ['x-large', 'xl', 'modal-xl'];\n\n export function fromString(size?: string): DialogSize {\n if (size === undefined) return defaultDialogSize;\n if (largeIdentifiers.includes(size)) return DialogSize.LARGE;\n if (mediumIdentifiers.includes(size)) return DialogSize.MEDIUM;\n if (smallIdentifiers.includes(size)) return DialogSize.SMALL;\n if (xLargeIdentifiers.includes(size)) return DialogSize.X_LARGE;\n return defaultDialogSize;\n }\n\n export function isDefined(size: number | string) {\n const check = (typeof size === 'number') ? size : DialogSize.fromString(size as string);\n return Object.values(DialogSize).includes(check);\n }\n}\n\nObject.freeze(DialogSize);\nexport default DialogSize;\n","import { computed, ComputedRef, ref } from 'vue';\n\nclass DialogTracker {\n private stack: symbol[] = [];\n\n public currentRef = ref<symbol | null>(null);\n\n push(sym: symbol): void {\n this.stack.push(sym);\n this.currentRef.value = sym;\n }\n\n isTop(sym: symbol): ComputedRef<boolean> {\n return computed(() => this.currentRef.value === sym);\n }\n\n remove(sym: symbol): void {\n const index = this.stack.indexOf(sym);\n if (index !== -1) {\n this.stack.splice(index, 1);\n this.currentRef.value = this.stack[this.stack.length - 1] || null;\n }\n }\n}\n\nconst dialogTracker = new DialogTracker();\n\nexport default dialogTracker;\n","/* eslint-disable class-methods-use-this */\n// eslint-disable-next-line max-classes-per-file\nimport * as Form from '@dynamicforms/vue-forms';\nimport { Action } from '@dynamicforms/vuetify-inputs';\nimport { isEmpty } from 'lodash-es';\nimport { computed, ref } from 'vue';\n\n// import { Action, ActionCollection, FilteredActions } from '@/actions';\nimport DialogSize from './dialog-size';\nimport dialogTracker from './top-modal-tracker';\n\nexport type FormActions = Record<string, Action>;\n\nexport interface CloseablePromise<T> extends Promise<T> {\n close: (value: T) => void;\n dialogId: symbol;\n}\n\nexport interface ModalOptions {\n form?: Form.Group;\n size?: DialogSize;\n actions?: FormActions;\n color?: string;\n icon?: string;\n}\n\nexport interface ModalData extends ModalOptions {\n dialogId: symbol;\n title: Form.RenderContent;\n message: Form.RenderContent;\n size: DialogSize;\n resolve: (value: string) => void;\n}\n\nconst modalDefinitions = {} as Record<symbol, ModalData>;\nexport const installed = ref(false);\n\nclass ModalAPI {\n isTop(promise: CloseablePromise<any>) {\n return dialogTracker.isTop(promise.dialogId).value;\n }\n\n isInstalled() {\n return installed.value;\n }\n\n yesNo(title: Form.RenderContent, message: Form.RenderContent, options?: ModalOptions): CloseablePromise<string> {\n const hasAction = Object.keys(options?.form?.fields ?? []).some((fieldName) => (\n options?.form?.field(fieldName) instanceof Form.Action\n )) || !isEmpty(options?.actions);\n\n const yes = Action.yesAction();\n Object.defineProperty(yes, 'defaultConfirm', { value: true });\n const no = Action.noAction();\n Object.defineProperty(no, 'defaultReject', { value: true });\n\n return this.messageInternal(title, message, hasAction ? { } : { yes, no }, options);\n }\n\n message(title: Form.RenderContent, message: Form.RenderContent, options?: ModalOptions): CloseablePromise<string> {\n const hasAction = Object.keys(options?.form?.fields ?? []).some((fieldName) => (\n options?.form?.field(fieldName) instanceof Form.Action\n )) || !isEmpty(options?.actions);\n\n const close = Action.closeAction();\n Object.defineProperties(close, {\n defaultConfirm: { value: true },\n defaultReject: { value: true },\n });\n\n return this.messageInternal(title, message, hasAction ? { } : { close }, options);\n }\n\n custom(title: Form.RenderContent, componentName: string, componentProps: Record<any, any>, options?: ModalOptions)\n : CloseablePromise<string> {\n return this.message(title, <Form.CustomModalContentComponentDef>{ componentName, componentProps }, options);\n }\n\n private messageInternal(\n title: Form.RenderContent,\n message: Form.RenderContent,\n defaultActions: FormActions,\n options?: ModalOptions,\n ): CloseablePromise<string> {\n // Object.keys(defaultActions).forEach((actionName) => {\n // if (form.field(actionName) == null) form.fields[actionName] = defaultActions[actionName] as Action;\n // });\n\n let resolvePromise: (value: string) => void;\n\n const actions: FormActions = { ...defaultActions, ...(options?.actions ?? { }) };\n\n Object.keys(options?.form?.fields ?? []).forEach((fieldName) => {\n const action = options?.form?.field(fieldName);\n if (action instanceof Form.Action) {\n if (!actions[fieldName]) {\n actions[fieldName] = <Action><any> action;\n } else {\n action.registerAction(new Form.ExecuteAction(async (field, supr, ...params) => {\n await supr(field, ...params);\n resolvePromise(field.fieldName!);\n }));\n }\n }\n });\n Object.entries(actions).forEach(([name, action]) => {\n action.registerAction(new Form.ExecuteAction(async (field, supr, ...params) => {\n await supr(field, ...params);\n resolvePromise(field.fieldName || name);\n }));\n });\n\n const id = Symbol('modalstack');\n const promise = new Promise<string>((resolve) => {\n resolvePromise = (value: string) => {\n resolve(value);\n dialogTracker.remove(id);\n delete modalDefinitions[id];\n };\n dialogTracker.push(id);\n modalDefinitions[id] = {\n dialogId: id,\n title,\n message,\n form: options?.form,\n size: options?.size ?? DialogSize.DEFAULT,\n actions,\n resolve,\n color: options?.color,\n icon: options?.icon,\n };\n }) as CloseablePromise<string>;\n\n promise.close = (value: string) => resolvePromise(value);\n promise.dialogId = id;\n\n return promise;\n }\n}\n\nconst modal = new ModalAPI();\nexport default modal;\n\nexport const currentModal = computed(() => {\n const currentId = dialogTracker.currentRef.value;\n return currentId ? modalDefinitions[currentId] : null;\n});\n","function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }\nfunction _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError(\"Cannot initialize the same private elements twice on an object\"); }\nfunction _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }\nfunction _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }\nfunction _assertClassBrand(e, t, n) { if (\"function\" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError(\"Private element is not present on this object\"); }\n// Utilities\nimport { capitalize, Comment, Fragment, isVNode, reactive, shallowRef, toRef, unref, watchEffect } from 'vue';\nimport { IN_BROWSER } from \"./globals.js\"; // Types\nexport function getNestedValue(obj, path, fallback) {\n const last = path.length - 1;\n if (last < 0) return obj === undefined ? fallback : obj;\n for (let i = 0; i < last; i++) {\n if (obj == null) {\n return fallback;\n }\n obj = obj[path[i]];\n }\n if (obj == null) return fallback;\n return obj[path[last]] === undefined ? fallback : obj[path[last]];\n}\nexport function deepEqual(a, b) {\n if (a === b) return true;\n if (a instanceof Date && b instanceof Date && a.getTime() !== b.getTime()) {\n // If the values are Date, compare them as timestamps\n return false;\n }\n if (a !== Object(a) || b !== Object(b)) {\n // If the values aren't objects, they were already checked for equality\n return false;\n }\n const props = Object.keys(a);\n if (props.length !== Object.keys(b).length) {\n // Different number of props, don't bother to check\n return false;\n }\n return props.every(p => deepEqual(a[p], b[p]));\n}\nexport function getObjectValueByPath(obj, path, fallback) {\n // credit: http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key#comment55278413_6491621\n if (obj == null || !path || typeof path !== 'string') return fallback;\n if (obj[path] !== undefined) return obj[path];\n path = path.replace(/\\[(\\w+)\\]/g, '.$1'); // convert indexes to properties\n path = path.replace(/^\\./, ''); // strip a leading dot\n return getNestedValue(obj, path.split('.'), fallback);\n}\nexport function getPropertyFromItem(item, property, fallback) {\n if (property === true) return item === undefined ? fallback : item;\n if (property == null || typeof property === 'boolean') return fallback;\n if (item !== Object(item)) {\n if (typeof property !== 'function') return fallback;\n const value = property(item, fallback);\n return typeof value === 'undefined' ? fallback : value;\n }\n if (typeof property === 'string') return getObjectValueByPath(item, property, fallback);\n if (Array.isArray(property)) return getNestedValue(item, property, fallback);\n if (typeof property !== 'function') return fallback;\n const value = property(item, fallback);\n return typeof value === 'undefined' ? fallback : value;\n}\nexport function createRange(length) {\n let start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n return Array.from({\n length\n }, (v, k) => start + k);\n}\nexport function getZIndex(el) {\n if (!el || el.nodeType !== Node.ELEMENT_NODE) return 0;\n const index = Number(window.getComputedStyle(el).getPropertyValue('z-index'));\n if (!index) return getZIndex(el.parentNode);\n return index;\n}\nexport function convertToUnit(str) {\n let unit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'px';\n if (str == null || str === '') {\n return undefined;\n }\n const num = Number(str);\n if (isNaN(num)) {\n return String(str);\n } else if (!isFinite(num)) {\n return undefined;\n } else {\n return `${num}${unit}`;\n }\n}\nexport function isObject(obj) {\n return obj !== null && typeof obj === 'object' && !Array.isArray(obj);\n}\nexport function isPlainObject(obj) {\n let proto;\n return obj !== null && typeof obj === 'object' && ((proto = Object.getPrototypeOf(obj)) === Object.prototype || proto === null);\n}\nexport function refElement(obj) {\n if (obj && '$el' in obj) {\n const el = obj.$el;\n if (el?.nodeType === Node.TEXT_NODE) {\n // Multi-root component, use the first element\n return el.nextElementSibling;\n }\n return el;\n }\n return obj;\n}\n\n// KeyboardEvent.keyCode aliases\nexport const keyCodes = Object.freeze({\n enter: 13,\n tab: 9,\n delete: 46,\n esc: 27,\n space: 32,\n up: 38,\n down: 40,\n left: 37,\n right: 39,\n end: 35,\n home: 36,\n del: 46,\n backspace: 8,\n insert: 45,\n pageup: 33,\n pagedown: 34,\n shift: 16\n});\nexport const keyValues = Object.freeze({\n enter: 'Enter',\n tab: 'Tab',\n delete: 'Delete',\n esc: 'Escape',\n space: 'Space',\n up: 'ArrowUp',\n down: 'ArrowDown',\n left: 'ArrowLeft',\n right: 'ArrowRight',\n end: 'End',\n home: 'Home',\n del: 'Delete',\n backspace: 'Backspace',\n insert: 'Insert',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n shift: 'Shift'\n});\nexport function keys(o) {\n return Object.keys(o);\n}\nexport function has(obj, key) {\n return key.every(k => obj.hasOwnProperty(k));\n}\n// Array of keys\nexport function pick(obj, paths) {\n const found = {};\n for (const key of paths) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n found[key] = obj[key];\n }\n }\n return found;\n}\n\n// Array of keys\n\n// Array of keys or RegExp to test keys against\n\nexport function pickWithRest(obj, paths, exclude) {\n const found = Object.create(null);\n const rest = Object.create(null);\n for (const key in obj) {\n if (paths.some(path => path instanceof RegExp ? path.test(key) : path === key) && !exclude?.some(path => path === key)) {\n found[key] = obj[key];\n } else {\n rest[key] = obj[key];\n }\n }\n return [found, rest];\n}\nexport function omit(obj, exclude) {\n const clone = {\n ...obj\n };\n exclude.forEach(prop => delete clone[prop]);\n return clone;\n}\nconst onRE = /^on[^a-z]/;\nexport const isOn = key => onRE.test(key);\nconst bubblingEvents = ['onAfterscriptexecute', 'onAnimationcancel', 'onAnimationend', 'onAnimationiteration', 'onAnimationstart', 'onAuxclick', 'onBeforeinput', 'onBeforescriptexecute', 'onChange', 'onClick', 'onCompositionend', 'onCompositionstart', 'onCompositionupdate', 'onContextmenu', 'onCopy', 'onCut', 'onDblclick', 'onFocusin', 'onFocusout', 'onFullscreenchange', 'onFullscreenerror', 'onGesturechange', 'onGestureend', 'onGesturestart', 'onGotpointercapture', 'onInput', 'onKeydown', 'onKeypress', 'onKeyup', 'onLostpointercapture', 'onMousedown', 'onMousemove', 'onMouseout', 'onMouseover', 'onMouseup', 'onMousewheel', 'onPaste', 'onPointercancel', 'onPointerdown', 'onPointerenter', 'onPointerleave', 'onPointermove', 'onPointerout', 'onPointerover', 'onPointerup', 'onReset', 'onSelect', 'onSubmit', 'onTouchcancel', 'onTouchend', 'onTouchmove', 'onTouchstart', 'onTransitioncancel', 'onTransitionend', 'onTransitionrun', 'onTransitionstart', 'onWheel'];\nconst compositionIgnoreKeys = ['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Enter', 'Escape', 'Tab', ' '];\nexport function isComposingIgnoreKey(e) {\n return e.isComposing && compositionIgnoreKeys.includes(e.key);\n}\n\n/**\n * Filter attributes that should be applied to\n * the root element of an input component. Remaining\n * attributes should be passed to the <input> element inside.\n */\nexport function filterInputAttrs(attrs) {\n const [events, props] = pickWithRest(attrs, [onRE]);\n const inputEvents = omit(events, bubblingEvents);\n const [rootAttrs, inputAttrs] = pickWithRest(props, ['class', 'style', 'id', /^data-/]);\n Object.assign(rootAttrs, events);\n Object.assign(inputAttrs, inputEvents);\n return [rootAttrs, inputAttrs];\n}\n\n/**\n * Returns the set difference of B and A, i.e. the set of elements in B but not in A\n */\nexport function arrayDiff(a, b) {\n const diff = [];\n for (let i = 0; i < b.length; i++) {\n if (!a.includes(b[i])) diff.push(b[i]);\n }\n return diff;\n}\nexport function wrapInArray(v) {\n return v == null ? [] : Array.isArray(v) ? v : [v];\n}\nexport function defaultFilter(value, search, item) {\n return value != null && search != null && typeof value !== 'boolean' && value.toString().toLocaleLowerCase().indexOf(search.toLocaleLowerCase()) !== -1;\n}\nexport function debounce(fn, delay) {\n let timeoutId = 0;\n const wrap = function () {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), unref(delay));\n };\n wrap.clear = () => {\n clearTimeout(timeoutId);\n };\n wrap.immediate = fn;\n return wrap;\n}\nexport function throttle(fn, limit) {\n let throttling = false;\n return function () {\n if (!throttling) {\n throttling = true;\n setTimeout(() => throttling = false, limit);\n return fn(...arguments);\n }\n };\n}\nexport function clamp(value) {\n let min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n let max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;\n return Math.max(min, Math.min(max, value));\n}\nexport function getDecimals(value) {\n const trimmedStr = value.toString().trim();\n return trimmedStr.includes('.') ? trimmedStr.length - trimmedStr.indexOf('.') - 1 : 0;\n}\nexport function padEnd(str, length) {\n let char = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0';\n return str + char.repeat(Math.max(0, length - str.length));\n}\nexport function padStart(str, length) {\n let char = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0';\n return char.repeat(Math.max(0, length - str.length)) + str;\n}\nexport function chunk(str) {\n let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;\n const chunked = [];\n let index = 0;\n while (index < str.length) {\n chunked.push(str.substr(index, size));\n index += size;\n }\n return chunked;\n}\nexport function chunkArray(array) {\n let size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;\n return Array.from({\n length: Math.ceil(array.length / size)\n }, (v, i) => array.slice(i * size, i * size + size));\n}\nexport function humanReadableFileSize(bytes) {\n let base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;\n if (bytes < base) {\n return `${bytes} B`;\n }\n const prefix = base === 1024 ? ['Ki', 'Mi', 'Gi'] : ['k', 'M', 'G'];\n let unit = -1;\n while (Math.abs(bytes) >= base && unit < prefix.length - 1) {\n bytes /= base;\n ++unit;\n }\n return `${bytes.toFixed(1)} ${prefix[unit]}B`;\n}\nexport function mergeDeep() {\n let source = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let arrayFn = arguments.length > 2 ? arguments[2] : undefined;\n const out = {};\n for (const key in source) {\n out[key] = source[key];\n }\n for (const key in target) {\n const sourceProperty = source[key];\n const targetProperty = target[key];\n\n // Only continue deep merging if\n // both properties are plain objects\n if (isPlainObject(sourceProperty) && isPlainObject(targetProperty)) {\n out[key] = mergeDeep(sourceProperty, targetProperty, arrayFn);\n continue;\n }\n if (arrayFn && Array.isArray(sourceProperty) && Array.isArray(targetProperty)) {\n out[key] = arrayFn(sourceProperty, targetProperty);\n continue;\n }\n out[key] = targetProperty;\n }\n return out;\n}\nexport function flattenFragments(nodes) {\n return nodes.map(node => {\n if (node.type === Fragment) {\n return flattenFragments(node.children);\n } else {\n return node;\n }\n }).flat();\n}\nexport function toKebabCase() {\n let str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n if (toKebabCase.cache.has(str)) return toKebabCase.cache.get(str);\n const kebab = str.replace(/[^a-z]/gi, '-').replace(/\\B([A-Z])/g, '-$1').toLowerCase();\n toKebabCase.cache.set(str, kebab);\n return kebab;\n}\ntoKebabCase.cache = new Map();\nexport function findChildrenWithProvide(key, vnode) {\n if (!vnode || typeof vnode !== 'object') return [];\n if (Array.isArray(vnode)) {\n return vnode.map(child => findChildrenWithProvide(key, child)).flat(1);\n } else if (vnode.suspense) {\n return findChildrenWithProvide(key, vnode.ssContent);\n } else if (Array.isArray(vnode.children)) {\n return vnode.children.map(child => findChildrenWithProvide(key, child)).flat(1);\n } else if (vnode.component) {\n if (Object.getOwnPropertySymbols(vnode.component.provides).includes(key)) {\n return [vnode.component];\n } else if (vnode.component.subTree) {\n return findChildrenWithProvide(key, vnode.component.subTree).flat(1);\n }\n }\n return [];\n}\nvar _arr = /*#__PURE__*/new WeakMap();\nvar _pointer = /*#__PURE__*/new WeakMap();\nexport class CircularBuffer {\n constructor(size) {\n _classPrivateFieldInitSpec(this, _arr, []);\n _classPrivateFieldInitSpec(this, _pointer, 0);\n this.size = size;\n }\n get isFull() {\n return _classPrivateFieldGet(_arr, this).length === this.size;\n }\n push(val) {\n _classPrivateFieldGet(_arr, this)[_classPrivateFieldGet(_pointer, this)] = val;\n _classPrivateFieldSet(_pointer, this, (_classPrivateFieldGet(_pointer, this) + 1) % this.size);\n }\n values() {\n return _classPrivateFieldGet(_arr, this).slice(_classPrivateFieldGet(_pointer, this)).concat(_classPrivateFieldGet(_arr, this).slice(0, _classPrivateFieldGet(_pointer, this)));\n }\n clear() {\n _classPrivateFieldGet(_arr, this).length = 0;\n _classPrivateFieldSet(_pointer, this, 0);\n }\n}\nexport function getEventCoordinates(e) {\n if ('touches' in e) {\n return {\n clientX: e.touches[0].clientX,\n clientY: e.touches[0].clientY\n };\n }\n return {\n clientX: e.clientX,\n clientY: e.clientY\n };\n}\n\n// Only allow a single return type\n\n/**\n * Convert a computed ref to a record of refs.\n * The getter function must always return an object with the same keys.\n */\n\nexport function destructComputed(getter) {\n const refs = reactive({});\n watchEffect(() => {\n const base = getter();\n for (const key in base) {\n refs[key] = base[key];\n }\n }, {\n flush: 'sync'\n });\n const obj = {};\n for (const key in refs) {\n obj[key] = toRef(() => refs[key]);\n }\n return obj;\n}\n\n/** Array.includes but value can be any type */\nexport function includes(arr, val) {\n return arr.includes(val);\n}\nexport function eventName(propName) {\n return propName[2].toLowerCase() + propName.slice(3);\n}\n\n// TODO: this should be an array but vue's types don't accept arrays: vuejs/core#8025\n\nexport const EventProp = () => [Function, Array];\nexport function hasEvent(props, name) {\n name = 'on' + capitalize(name);\n return !!(props[name] || props[`${name}Once`] || props[`${name}Capture`] || props[`${name}OnceCapture`] || props[`${name}CaptureOnce`]);\n}\nexport function callEvent(handler) {\n for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n args[_key2 - 1] = arguments[_key2];\n }\n if (Array.isArray(handler)) {\n for (const h of handler) {\n h(...args);\n }\n } else if (typeof handler === 'function') {\n handler(...args);\n }\n}\nexport function focusableChildren(el) {\n let filterByTabIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n const targets = ['button', '[href]', 'input:not([type=\"hidden\"])', 'select', 'textarea', '[tabindex]'].map(s => `${s}${filterByTabIndex ? ':not([tabindex=\"-1\"])' : ''}:not([disabled])`).join(', ');\n return [...el.querySelectorAll(targets)];\n}\nexport function getNextElement(elements, location, condition) {\n let _el;\n let idx = elements.indexOf(document.activeElement);\n const inc = location === 'next' ? 1 : -1;\n do {\n idx += inc;\n _el = elements[idx];\n } while ((!_el || _el.offsetParent == null || !(condition?.(_el) ?? true)) && idx < elements.length && idx >= 0);\n return _el;\n}\nexport function focusChild(el, location) {\n const focusable = focusableChildren(el);\n if (!location) {\n if (el === document.activeElement || !el.contains(document.activeElement)) {\n focusable[0]?.focus();\n }\n } else if (location === 'first') {\n focusable[0]?.focus();\n } else if (location === 'last') {\n focusable.at(-1)?.focus();\n } else if (typeof location === 'number') {\n focusable[location]?.focus();\n } else {\n const _el = getNextElement(focusable, location);\n if (_el) _el.focus();else focusChild(el, location === 'next' ? 'first' : 'last');\n }\n}\nexport function isEmpty(val) {\n return val === null || val === undefined || typeof val === 'string' && val.trim() === '';\n}\nexport function noop() {}\n\n/** Returns null if the selector is not supported or we can't check */\nexport function matchesSelector(el, selector) {\n const supportsSelector = IN_BROWSER && typeof CSS !== 'undefined' && typeof CSS.supports !== 'undefined' && CSS.supports(`selector(${selector})`);\n if (!supportsSelector) return null;\n try {\n return !!el && el.matches(selector);\n } catch (err) {\n return null;\n }\n}\nexport function ensureValidVNode(vnodes) {\n return vnodes.some(child => {\n if (!isVNode(child)) return true;\n if (child.type === Comment) return false;\n return child.type !== Fragment || ensureValidVNode(child.children);\n }) ? vnodes : null;\n}\nexport function defer(timeout, cb) {\n if (!IN_BROWSER || timeout === 0) {\n cb();\n return () => {};\n }\n const timeoutId = window.setTimeout(cb, timeout);\n return () => window.clearTimeout(timeoutId);\n}\nexport function isClickInsideElement(event, targetDiv) {\n const mouseX = event.clientX;\n const mouseY = event.clientY;\n const divRect = targetDiv.getBoundingClientRect();\n const divLeft = divRect.left;\n const divTop = divRect.top;\n const divRight = divRect.right;\n const divBottom = divRect.bottom;\n return mouseX >= divLeft && mouseX <= divRight && mouseY >= divTop && mouseY <= divBottom;\n}\nexport function templateRef() {\n const el = shallowRef();\n const fn = target => {\n el.value = target;\n };\n Object.defineProperty(fn, 'value', {\n enumerable: true,\n get: () => el.value,\n set: val => el.value = val\n });\n Object.defineProperty(fn, 'el', {\n enumerable: true,\n get: () => refElement(el.value)\n });\n return fn;\n}\nexport function checkPrintable(e) {\n const isPrintableChar = e.key.length === 1;\n const noModifier = !e.ctrlKey && !e.metaKey && !e.altKey;\n return isPrintableChar && noModifier;\n}\nexport function isPrimitive(value) {\n return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint';\n}\n//# sourceMappingURL=helpers.js.map","// Utilities\nimport { getCurrentInstance as _getCurrentInstance } from 'vue';\nimport { toKebabCase } from \"./helpers.js\";\nexport function getCurrentInstance(name, message) {\n const vm = _getCurrentInstance();\n if (!vm) {\n throw new Error(`[Vuetify] ${name} ${message || 'must be called from inside a setup function'}`);\n }\n return vm;\n}\nexport function getCurrentInstanceName() {\n let name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'composables';\n const vm = getCurrentInstance(name).type;\n return toKebabCase(vm?.aliasName || vm?.name);\n}\n//# sourceMappingURL=getCurrentInstance.js.map","// Utilities\nimport { computed, inject, onScopeDispose, reactive, shallowRef, toRef, toRefs, watchEffect } from 'vue';\nimport { getCurrentInstanceName, mergeDeep, propsFactory } from \"../util/index.js\";\nimport { IN_BROWSER, SUPPORTS_TOUCH } from \"../util/globals.js\"; // Types\nexport const breakpoints = ['sm', 'md', 'lg', 'xl', 'xxl']; // no xs\n\nexport const DisplaySymbol = Symbol.for('vuetify:display');\nconst defaultDisplayOptions = {\n mobileBreakpoint: 'lg',\n thresholds: {\n xs: 0,\n sm: 600,\n md: 960,\n lg: 1280,\n xl: 1920,\n xxl: 2560\n }\n};\nconst parseDisplayOptions = function () {\n let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultDisplayOptions;\n return mergeDeep(defaultDisplayOptions, options);\n};\nfunction getClientWidth(ssr) {\n return IN_BROWSER && !ssr ? window.innerWidth : typeof ssr === 'object' && ssr.clientWidth || 0;\n}\nfunction getClientHeight(ssr) {\n return IN_BROWSER && !ssr ? window.innerHeight : typeof ssr === 'object' && ssr.clientHeight || 0;\n}\nfunction getPlatform(ssr) {\n const userAgent = IN_BROWSER && !ssr ? window.navigator.userAgent : 'ssr';\n function match(regexp) {\n return Boolean(userAgent.match(regexp));\n }\n const android = match(/android/i);\n const ios = match(/iphone|ipad|ipod/i);\n const cordova = match(/cordova/i);\n const electron = match(/electron/i);\n const chrome = match(/chrome/i);\n const edge = match(/edge/i);\n const firefox = match(/firefox/i);\n const opera = match(/opera/i);\n const win = match(/win/i);\n const mac = match(/mac/i);\n const linux = match(/linux/i);\n return {\n android,\n ios,\n cordova,\n electron,\n chrome,\n edge,\n firefox,\n opera,\n win,\n mac,\n linux,\n touch: SUPPORTS_TOUCH,\n ssr: userAgent === 'ssr'\n };\n}\nexport function createDisplay(options, ssr) {\n const {\n thresholds,\n mobileBreakpoint\n } = parseDisplayOptions(options);\n const height = shallowRef(getClientHeight(ssr));\n const platform = shallowRef(getPlatform(ssr));\n const state = reactive({});\n const width = shallowRef(getClientWidth(ssr));\n function updateSize() {\n height.value = getClientHeight();\n width.value = getClientWidth();\n }\n function update() {\n updateSize();\n platform.value = getPlatform();\n }\n\n // eslint-disable-next-line max-statements\n watchEffect(() => {\n const xs = width.value < thresholds.sm;\n const sm = width.value < thresholds.md && !xs;\n const md = width.value < thresholds.lg && !(sm || xs);\n const lg = width.value < thresholds.xl && !(md || sm || xs);\n const xl = width.value < thresholds.xxl && !(lg || md || sm || xs);\n const xxl = width.value >= thresholds.xxl;\n const name = xs ? 'xs' : sm ? 'sm' : md ? 'md' : lg ? 'lg' : xl ? 'xl' : 'xxl';\n const breakpointValue = typeof mobileBreakpoint === 'number' ? mobileBreakpoint : thresholds[mobileBreakpoint];\n const mobile = width.value < breakpointValue;\n state.xs = xs;\n state.sm = sm;\n state.md = md;\n state.lg = lg;\n state.xl = xl;\n state.xxl = xxl;\n state.smAndUp = !xs;\n state.mdAndUp = !(xs || sm);\n state.lgAndUp = !(xs || sm || md);\n state.xlAndUp = !(xs || sm || md || lg);\n state.smAndDown = !(md || lg || xl || xxl);\n state.mdAndDown = !(lg || xl || xxl);\n state.lgAndDown = !(xl || xxl);\n state.xlAndDown = !xxl;\n state.name = name;\n state.height = height.value;\n state.width = width.value;\n state.mobile = mobile;\n state.mobileBreakpoint = mobileBreakpoint;\n state.platform = platform.value;\n state.thresholds = thresholds;\n });\n if (IN_BROWSER) {\n window.addEventListener('resize', updateSize, {\n passive: true\n });\n onScopeDispose(() => {\n window.removeEventListener('resize', updateSize);\n }, true);\n }\n return {\n ...toRefs(state),\n update,\n ssr: !!ssr\n };\n}\nexport const makeDisplayProps = propsFactory({\n mobile: {\n type: Boolean,\n default: false\n },\n mobileBreakpoint: [Number, String]\n}, 'display');\nexport function useDisplay() {\n let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {\n mobile: null\n };\n let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getCurrentInstanceName();\n const display = inject(DisplaySymbol);\n if (!display) throw new Error('Could not find Vuetify display injection');\n const mobile = computed(() => {\n if (props.mobile) {\n return true;\n } else if (typeof props.mobileBreakpoint === 'number') {\n return display.width.value < props.mobileBreakpoint;\n } else if (props.mobileBreakpoint) {\n return display.width.value < display.thresholds.value[props.mobileBreakpoint];\n } else if (props.mobile === null) {\n return display.mobile.value;\n } else {\n return false;\n }\n });\n const displayClasses = toRef(() => {\n if (!name) return {};\n return {\n [`${name}--mobile`]: mobile.value\n };\n });\n return {\n ...display,\n displayClasses,\n mobile\n };\n}\n//# sourceMappingURL=display.js.map","<template>\n <!--https://stackoverflow.com/questions/55085735/vuetify-v-dialog-dynamic-width-->\n <v-dialog\n v-model=\"isShown\"\n :width=\"width\"\n :max-width=\"width\"\n :fullscreen=\"fullScreen\"\n :retain-focus=\"false\"\n persistent\n >\n <v-card>\n <v-card-title>\n <v-sheet\n :color=\"props.color || undefined\"\n :class=\"{ 'mx-n4 mt-n3 mb-3 d-flex align-center px-4 py-6': !!props.color, 'position-relative': closable }\"\n :elevation=\"!!props.color ? 4 : 0\"\n >\n <v-icon v-if=\"icon\" class=\"me-2\" :icon=\"icon\"/>\n <slot name=\"title\">\n <template v-if=\"!(title instanceof Form.MdString)\">{{ title }}</template>\n <vue-markdown v-else source=\"title\"/>\n </slot>\n <v-btn\n v-if=\"closable\"\n icon\n variant=\"text\"\n class=\"position-absolute\"\n style=\"right: 0.25em\"\n @click=\"onModelValueUpdate(false)\"\n >\n <v-icon icon=\"mdi-close\"/>\n </v-btn>\n </v-sheet>\n </v-card-title>\n <v-card-text>\n <slot name=\"body\" :form-control=\"formControl\"/>\n </v-card-text>\n <v-card-actions>\n <div style=\"flex:1\">\n <slot name=\"actions\"/>\n </div>\n </v-card-actions>\n </v-card>\n </v-dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport * as Form from '@dynamicforms/vue-forms';\nimport { computed, onUnmounted, watch } from 'vue';\nimport VueMarkdown from 'vue-markdown-render';\nimport { useDisplay } from 'vuetify';\n\nimport DialogSize from './dialog-size';\nimport dialogTracker from './top-modal-tracker';\n\ninterface Props {\n modelValue: boolean;\n closable?: boolean;\n size?: DialogSize;\n formControl?: Form.Group;\n dialogId?: symbol;\n title?: Form.RenderContent;\n color?: string;\n icon?: string;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: false,\n closable: false,\n size: DialogSize.DEFAULT,\n dialogId: undefined,\n formControl: undefined,\n title: undefined,\n color: undefined,\n icon: undefined,\n});\nconst display = useDisplay();\nconst size = computed(() => props.size);\n\nconst fullScreen = computed(() => {\n if (size.value === DialogSize.SMALL && !display.smAndUp.value) return true;\n if (size.value === DialogSize.MEDIUM && !display.mdAndUp.value) return true;\n if (size.value === DialogSize.LARGE && !display.lgAndUp.value) return true;\n return size.value === DialogSize.X_LARGE && !display.xl.value;\n});\n\nconst width = computed<'unset' | number>(() => {\n if (fullScreen.value) return 'unset';\n switch (size.value) {\n case DialogSize.SMALL:\n return 400;\n case DialogSize.MEDIUM:\n return 600;\n case DialogSize.LARGE:\n return 800;\n case DialogSize.X_LARGE:\n return 1140;\n default:\n return 'unset';\n }\n});\n\nconst sym = computed(() => (props.dialogId ?? Symbol('df-dialog')));\nconst isTop = dialogTracker.isTop(sym.value);\nconst emit = defineEmits<{\n 'update:model-value': [value: boolean]\n}>();\n\nfunction onModelValueUpdate(value: boolean, dontEmit = false) {\n if (!props.dialogId || !value) {\n // manage stack only if this dialog is a template-one, not managed by api.ts\n if (value) {\n dialogTracker.push(sym.value);\n } else {\n dialogTracker.remove(sym.value);\n }\n }\n if (!dontEmit) emit('update:model-value', value);\n}\n\nconst isShown = computed(() => props.modelValue && isTop.value);\n\nwatch(() => props.modelValue, (newValue, oldValue) => {\n if (newValue !== oldValue) onModelValueUpdate(newValue, true);\n}, { immediate: true });\n\nonUnmounted(() => {\n dialogTracker.remove(sym.value);\n});\n\ntype Slots = {\n title: () => any;\n body: (props: { formControl: Form.Group }) => Form.Group;\n actions: () => any;\n};\n\ndefineSlots<Slots>();\n</script>\n","<template>\n <df-modal\n v-if=\"currentModal\"\n v-model=\"isOpen\"\n :form-control=\"currentModal.form\"\n :size=\"currentModal.size\"\n :dialog-id=\"currentModal.dialogId\"\n :title=\"currentModal.title\"\n :color=\"currentModal.color\"\n :icon=\"currentModal.icon\"\n >\n <template #body>\n <template v-if=\"bodyType === 'string'\">{{ currentModal.message }}</template>\n <vue-markdown v-else-if=\"bodyType === 'md'\" :source=\"String(currentModal.message)\"/>\n <template v-else><component :is=\"componentInfo?.componentName\" v-bind=\"componentInfo?.componentProps\"/></template>\n </template>\n <template #actions>\n <df-actions\n :actions=\"Object.values(currentModal.actions ?? [] as Action[])\"\n class=\"d-flex justify-end\"\n style=\"gap: .5em\"\n />\n </template>\n </df-modal>\n</template>\n\n<script setup lang=\"ts\">\nimport { isCustomModalContentComponentDef, MdString } from '@dynamicforms/vue-forms';\nimport { DfActions, Action } from '@dynamicforms/vuetify-inputs';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\nimport VueMarkdown from 'vue-markdown-render';\n\nimport { currentModal, installed } from './api';\nimport DfModal from './df-modal.component.vue';\n\nconst isOpen = ref(false);\n\nwatch(() => currentModal.value, (modal) => {\n isOpen.value = modal !== null;\n});\n\nconst bodyType = computed(() => {\n const msg = currentModal?.value?.message;\n if (!msg) return 'string';\n if (msg instanceof MdString) return 'md';\n if (isCustomModalContentComponentDef(msg)) return 'component';\n return 'string';\n});\n\nconst componentInfo = computed(\n () => (isCustomModalContentComponentDef(currentModal?.value?.message) ? currentModal?.value?.message : null),\n);\n\nonMounted(() => {\n if (installed.value) {\n console.warn('Seems like there is more than one df-modal-api in the v-dom');\n }\n installed.value = true;\n});\n\nonUnmounted(() => {\n installed.value = false;\n});\n</script>\n","import { BreakpointNames } from '@dynamicforms/vuetify-inputs';\n\nexport const FormBuilderName = Symbol('FormBuilder');\nexport const FormBuilderBodyProp = Symbol('FormBuilderBodyProp');\n\ntype BaseBkpt = BreakpointNames | 'base';\n\nexport interface FormJSON {\n rows: RowJSON[];\n}\nexport type FormJSONResponsive = FormJSON & {\n [key in BreakpointNames]?: FormJSON;\n};\n\n// row declarations\ninterface CSSProperties { [key: string]: string | number; }\n\ntype Align = 'start' | 'center' | 'end' | 'baseline' | 'stretch';\ntype AlignProps = { [K in BaseBkpt as K extends 'base' ? 'align' : `align-${K}`]?: Align };\n\ntype AlignContent = 'start' | 'center' | 'end' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly';\ntype AlignContentProps = {\n [K in BaseBkpt as K extends 'base' ? 'align-content' : `align-content-${K}`]?: AlignContent\n};\n\ntype Justify = 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';\ntype JustifyProps = { [K in BaseBkpt as K extends 'base' ? 'justify' : `justify-${K}`]?: Justify };\n\nexport interface RowProps extends AlignProps, AlignContentProps, JustifyProps {\n dense?: boolean;\n noGutters?: boolean;\n class?: string | Record<string, boolean> | string[];\n style?: string | CSSProperties | (string | CSSProperties)[];\n}\n\nexport type RowPropsPartial = Partial<RowProps>;\n\nexport interface RowJSON {\n props: RowPropsPartial;\n columns: ColumnJSON[];\n}\nexport type RowJSONResponsive = RowJSON & {\n [key in BreakpointNames]?: RowJSON;\n};\n\n// column declaractions\n\ntype ColsProps = { [K in BaseBkpt as K extends 'base' ? 'cols' : `cols-${K}`]?: number | 'auto' | boolean; };\ntype OffsetProps = { [K in BaseBkpt as K extends 'base' ? 'offset' : `offset-${K}`]?: number | 'auto' | boolean; };\ntype OrderProps = { [K in BaseBkpt as K extends 'base' ? 'order' : `order-${K}`]?: number | 'auto' | boolean; };\n\nexport interface ColumnProps extends ColsProps, OffsetProps, OrderProps {\n alignSelf?: 'start' | 'end' | 'center' | 'auto' | 'baseline' | 'stretch';\n class?: string | Record<string, boolean> | string[];\n style?: string | CSSProperties | (string | CSSProperties)[];\n}\nexport type ColumnPropsPartial = Partial<ColumnProps>;\n\nexport interface ColumnJSON {\n props: ColumnPropsPartial;\n components: ComponentJSON[];\n}\nexport type ColumnJSONResponsive = ColumnJSON & {\n [key in BreakpointNames]?: ColumnJSON;\n};\n\n// component declarations\nexport type ComponentProps<T extends Record<string | symbol, any> = Record<string | symbol, any>> = T & {\n toJSON?: (breakpoint?: BreakpointNames) => any;\n};\n\nexport interface ComponentJSON<T extends ComponentProps = ComponentProps> {\n name: string | symbol;\n props: T;\n}\n\nexport type TwelveDivisible = 1 | 2 | 3 | 4 | 6 | 12;\n","// eslint-disable-next-line max-classes-per-file\nimport type { FormBuilder } from '../form-builder';\nimport { ComponentJSON, ComponentProps, FormBuilderName } from '../types';\n\nexport class Component<T extends Record<string, any> = Record<string, any>> {\n name: string | symbol;\n\n props?: ComponentProps<T>;\n\n constructor(name: string | symbol, props?: ComponentProps<T>) {\n this.name = name;\n this.props = props;\n }\n\n toJSON(): ComponentJSON {\n return {\n name: this.name,\n props: this.props ? { ...(this.props.toJSON?.() ?? this.props) } : null,\n };\n }\n}\n\nexport interface ComponentBuilderInterface<T = any> {\n generic<P extends ComponentProps = ComponentProps>(name: string | symbol, props: P): T;\n}\n\nexport class ComponentBuilderBase implements ComponentBuilderInterface<ComponentBuilderBase> {\n constructor(private addCallback: (component: Component) => void) {}\n\n generic<P extends ComponentProps = ComponentProps>(name: string | symbol, props: P): this {\n const component = new Component<P>(name, props);\n this.addCallback(component);\n return this;\n }\n\n nestedForm(form: FormBuilder): this {\n return this.generic(FormBuilderName, form);\n }\n}\n","import { DfInputComponentProps } from '@dynamicforms/vuetify-inputs';\n\nimport { ComponentBuilderBase } from './component';\n\n// eslint-disable-next-line import/prefer-default-export\nexport class VuetifyInputsComponentBuilder extends ComponentBuilderBase {\n dfActions(props: Partial<DfInputComponentProps.DfActionsProps>) {\n return this.generic('df-actions', props);\n }\n\n dfCheckbox(props: Partial<DfInputComponentProps.DfCheckboxProps>) {\n return this.generic('df-checkbox', props);\n }\n\n dfColor(props: Partial<DfInputComponentProps.DfColorProps>) {\n return this.generic('df-color', props);\n }\n\n dfDateTime(props: Partial<DfInputComponentProps.DfDateTimeProps>) {\n return this.generic('df-date-time', props);\n }\n\n dfFile(props: Partial<DfInputComponentProps.DfFileProps>) {\n return this.generic('df-file', props);\n }\n\n dfInput(props: Partial<DfInputComponentProps.DfInputProps>) {\n return this.generic('df-input', props);\n }\n\n dfRtfEditor(props: Partial<DfInputComponentProps.DfRtfEditorProps>) {\n return this.generic('df-rtf-editor', props);\n }\n\n dfSelect(props: Partial<DfInputComponentProps.DfSelectProps>) {\n return this.generic('df-select', props);\n }\n\n dfTextArea(props: Partial<DfInputComponentProps.DfTextAreaProps>) {\n return this.generic('df-text-area', props);\n }\n}\n","// eslint-disable-next-line max-classes-per-file\nimport {\n BreakpointNames,\n BreakpointsJSON,\n responsiveBreakpoints,\n ResponsiveRenderOptions,\n} from '@dynamicforms/vuetify-inputs';\nimport { isArray, isBoolean, isNumber, isObjectLike, isString } from 'lodash-es';\n\nimport { Component, ComponentBuilderBase, VuetifyInputsComponentBuilder } from './component';\nimport { ColumnJSON, ColumnJSONResponsive, ColumnPropsPartial, ComponentProps } from './types';\n\nclass ColBase implements ComponentProps {\n props: ColumnPropsPartial;\n\n components: Component[] = [];\n\n constructor(props?: ColumnPropsPartial) {\n this.props = props ?? {};\n if (this.props.cols === undefined) this.props.cols = false;\n }\n\n component<T extends ComponentBuilderBase>(\n BuilderClass: { new(addCallback: (component: Component) => void): T },\n builderCallback: (builder: T) => T,\n ): this;\n component(\n builderCallback: (builder: VuetifyInputsComponentBuilder) => VuetifyInputsComponentBuilder,\n ): this;\n component<T extends ComponentBuilderBase>(param1: any, param2?: any): this {\n let BuilderClass: { new(addCallback: (component: Component) => void): T };\n let builderCallback: (builder: T) => T;\n if (param2) {\n BuilderClass = param1;\n builderCallback = param2;\n } else {\n BuilderClass = <{ new(addCallback: (component: Component) => void): T }><unknown>VuetifyInputsComponentBuilder;\n builderCallback = param1;\n }\n const builder = new BuilderClass((component: Component) => {\n this.components.push(component);\n });\n builderCallback(builder);\n return this;\n }\n\n /**\n * @return returns a proxy that allows to immediately from the column object add components, e.g.\n * new FormBuilder().row((row) => row.col((col) => col.simple.generic(...) will add one component into this column.\n * You may call the ComponentBuilder's methods as many times as you want to generate components\n */\n simple<T extends ComponentBuilderBase = VuetifyInputsComponentBuilder>(): T {\n const res = new Proxy({} as T, {\n get: (target: T, prop: string | symbol) => (\n (...args: any[]) => {\n this.component((cmpt : any) => cmpt[prop](...args));\n return res;\n }\n ),\n });\n return res;\n }\n\n toJSON(): ColumnJSON {\n return {\n props: this.props,\n components: this.components.map((cmpt) => cmpt.toJSON()),\n };\n }\n}\n\n// eslint-disable-next-line import/prefer-default-export\nexport class Column extends ResponsiveRenderOptions<ColBase> {\n constructor(props?: ColumnPropsPartial) {\n super({ props } as BreakpointsJSON<ColBase>);\n }\n\n component<T extends ComponentBuilderBase>(\n BuilderClass: { new(addCallback: (component: Component) => void): T },\n builderCallback: (builder: T) => T,\n ): this;\n component(\n builderCallback: (builder: VuetifyInputsComponentBuilder) => VuetifyInputsComponentBuilder,\n ): this;\n component<T extends ComponentBuilderBase>(param1: any, param2?: any): this {\n this._value.component<T>(param1, param2);\n return this;\n }\n\n breakpoint(breakpoint: BreakpointNames, colCallback: (col: ColBase) => ColBase): this {\n if (!this._value[breakpoint]) this._value[breakpoint] = new ColBase();\n colCallback(this._value[breakpoint]);\n return this;\n }\n\n /**\n * @return returns a proxy that allows to immediately from the column object add components, e.g.\n * new FormBuilder().row((row) => row.col((col) => col.simple.generic(...) will add one component into this column.\n * You may call the ComponentBuilder's methods as many times as you want to generate components\n */\n simple<T extends ComponentBuilderBase = VuetifyInputsComponentBuilder>(): T {\n return this._value.simple<T>();\n }\n\n toJSON(breakpoint?: BreakpointNames): ColumnJSONResponsive {\n if (breakpoint != null) {\n const res = this.getOptionsForBreakpoint(breakpoint);\n return {\n props: res.props,\n components: res.components.map((cmpt) => cmpt.toJSON()),\n };\n }\n const res: ColumnJSONResponsive = {\n props: this._value.props,\n components: this._value.components.map((cmpt) => cmpt.toJSON()),\n };\n responsiveBreakpoints.forEach((bp) => {\n if (this._value[bp]) res[bp] = this._value[bp].toJSON();\n });\n return res;\n }\n\n // eslint-disable-next-line class-methods-use-this\n protected cleanBreakpoint(bp?: ColBase, defaultIfEmpty: boolean = false): ColBase | null {\n if ((!bp || !isObjectLike(bp)) && !defaultIfEmpty) return null;\n\n const result: ColumnPropsPartial = {};\n\n const validAlignSelf = ['start', 'end', 'center', 'auto', 'baseline', 'stretch'];\n const isValidCols = (v: unknown): boolean => isNumber(v) || v === 'auto' || isBoolean(v);\n const isValidOffset = (v: unknown): boolean => isNumber(v);\n const isValidOrder = (v: unknown): boolean => isNumber(v);\n\n const isValidClass = (v: unknown): boolean => (\n isString(v) ||\n (isArray(v) && v.every((i) => isString(i))) ||\n (isObjectLike(v) && !Array.isArray(v))\n );\n\n const isValidStyle = (v: unknown): boolean => {\n if (isString(v)) return true;\n if (isArray(v)) return v.every(isValidStyle);\n if (isObjectLike(v)) {\n return Object.entries(v as object).every(([k, val]) => isString(k) && (isString(val) || isNumber(val)));\n }\n return false;\n };\n\n const baseKeys = ['cols', 'offset', 'order'];\n const validKeys = new Set<string>([\n ...baseKeys,\n ...responsiveBreakpoints.flatMap((b) => baseKeys.map((k) => `${k}-${b}`)),\n 'alignSelf',\n 'class',\n 'style',\n ]);\n\n const bpProps: ColumnPropsPartial = (bp ?? {}).props ?? { };\n Object.