props.onAnimationend()}\r\n >\r\n {slots.default && slots.default()}\r\n
\r\n )\r\n };\r\n }\r\n});\r\n","import \"@/styles/components/form.less\";\r\nimport { defineComponent, PropType, Teleport, VNode } from \"vue\";\r\nimport { Checkbox } from './Checkbox';\r\nimport { IActionBar, injectActionBar } from '../ActionBar';\r\nimport { UnreachableValueError } from '../misc';\r\nimport { Alert, AlertKind, AlertContainer, useAlertbar } from '../AlertBar';\r\n\r\nenum FormControlLayout {\r\n Normal = 0,\r\n Spread = 1\r\n}\r\n\r\nfunction getModifier(layout: FormControlLayout): string {\r\n switch(layout)\r\n {\r\n case FormControlLayout.Normal:\r\n return \"\";\r\n case FormControlLayout.Spread:\r\n return \"form__control--spread\";\r\n default:\r\n throw new UnreachableValueError(layout);\r\n }\r\n}\r\n\r\nexport const FormControl = defineComponent({\r\n props: {\r\n layout: {\r\n type: Number as PropType,\r\n default: FormControlLayout.Normal\r\n }\r\n },\r\n\r\n setup(props, { slots }) {\r\n const modifier: string = getModifier(props.layout);\r\n\r\n return () => (\r\n \r\n { slots.default && slots.default()}\r\n
\r\n );\r\n }\r\n});\r\n\r\nexport const TryOutForm = defineComponent({\r\n setup() {\r\n const actionBar: IActionBar | undefined = injectActionBar();\r\n\r\n const { alertbar, alerts} = useAlertbar();\r\n\r\n const addAlert = () => {\r\n alertbar.show(\r\n () => ( hello world),\r\n AlertKind.Warning\r\n );\r\n };\r\n\r\n const addAction = () => {\r\n if (!actionBar) {\r\n return;\r\n }\r\n actionBar.add(\"new action\");\r\n };\r\n\r\n return () => (\r\n \r\n );\r\n }\r\n});\r\n\r\nexport const Tabs = defineComponent({\r\n\r\n setup(props, { slots }) {\r\n const renderTabHeader = (a: VNode) => {\r\n return ({a.props?.title})\r\n }\r\n\r\n return () => {\r\n\r\n const children = slots.default ? slots.default() : [];\r\n\r\n return (\r\n \r\n
\r\n {children.map(x => renderTabHeader(x))}\r\n
\r\n\r\n {children}\r\n\r\n
\r\n );\r\n }\r\n }\r\n});\r\n\r\nexport const Tab = defineComponent({\r\n props: {\r\n title: {\r\n type: String,\r\n required: true\r\n }\r\n },\r\n\r\n setup(_, { slots }) {\r\n return () => (\r\n \r\n { slots.default && slots.default() }\r\n
\r\n );\r\n }\r\n});\r\n\r\nexport const Form = defineComponent({\r\n props: {\r\n horizontal: Boolean\r\n },\r\n\r\n setup(props, { slots }) {\r\n return () => (\r\n \r\n );\r\n }\r\n});\r\n\r\nexport const FormTextInput = defineComponent({\r\n props: {\r\n value: String,\r\n onChange: Function as PropType<(value: string) => void>,\r\n hasError: Boolean \r\n },\r\n\r\n setup(props) {\r\n \r\n return () => {\r\n let classes: string = \"form__input\";\r\n if (props.hasError) {\r\n classes += \" form__input--error\";\r\n }\r\n \r\n const onChange = (args: Event) => {\r\n if (props.onChange) {\r\n props.onChange((args.target as HTMLInputElement).value);\r\n }\r\n };\r\n\r\n return (\r\n \r\n );\r\n }\r\n }\r\n});\r\n\r\nexport const ValidationMessage = defineComponent({\r\n props: {\r\n text: {\r\n type: String\r\n }\r\n },\r\n\r\n setup (props) {\r\n\r\n return () => (\r\n <>\r\n { props.text && {props.text}}\r\n >\r\n )\r\n }\r\n})\r\n\r\nexport const FormLabel = defineComponent({\r\n props: {\r\n text: {\r\n type: String,\r\n required: true\r\n },\r\n for: {\r\n type: String,\r\n default: null\r\n }\r\n },\r\n\r\n setup(props) {\r\n return () => (\r\n \r\n );\r\n }\r\n});\r\n\r\nexport const FormItem = defineComponent({\r\n props: {\r\n label: {\r\n type: String,\r\n default: null\r\n },\r\n for: {\r\n type: String,\r\n default: null\r\n },\r\n fullWidth: {\r\n type: Boolean,\r\n default: false\r\n }\r\n },\r\n\r\n setup(props, { slots }) {\r\n return () => {\r\n return (\r\n \r\n );\r\n };\r\n }\r\n});\r\n","import \"@/styles/components/busy-indicator.less\";\r\nimport { defineComponent } from 'vue';\r\n\r\nexport const Spinner = defineComponent({\r\n\r\n setup() {\r\n\r\n return () => {\r\n return (\r\n \r\n )\r\n };\r\n }\r\n});\r\n\r\nexport const BusyIndicator = defineComponent({\r\n setup() {\r\n\r\n return () => {\r\n\r\n return (\r\n \r\n )\r\n };\r\n }\r\n});\r\n\r\nexport const BusyIndicatorContainer = defineComponent({\r\n props: {\r\n showBusyIndicator: {\r\n type: Boolean,\r\n required: false\r\n }\r\n },\r\n\r\n setup(props, { slots }) {\r\n return () => {\r\n return (\r\n \r\n { props.showBusyIndicator && }\r\n { slots.default && slots.default() }\r\n
\r\n );\r\n };\r\n }\r\n})","import { defineComponent, Teleport } from 'vue';\r\nimport \"@/styles/components/dialog.less\";\r\nimport { ActionIcon } from './ActionIcon';\r\nimport { BusyIndicatorContainer } from './BusyIndicator';\r\n\r\nexport const Dialog = defineComponent({\r\n props: {\r\n showBusyIndicator: {\r\n type: Boolean,\r\n required: false\r\n }\r\n },\r\n\r\n setup(props, { slots }) {\r\n\r\n return () => {\r\n\r\n return (\r\n \r\n \r\n
\r\n \r\n { slots.default && slots.default() }\r\n \r\n
\r\n
\r\n \r\n );\r\n };\r\n }\r\n});\r\n\r\nexport const DialogHeader = defineComponent({\r\n props: {\r\n title: {\r\n type: String,\r\n required: true\r\n },\r\n onClose: {\r\n type: Function,\r\n required: false\r\n }\r\n },\r\n\r\n setup(props, { slots }) {\r\n return () => {\r\n return (\r\n \r\n );\r\n };\r\n }\r\n});\r\n\r\nexport const DialogTitle = defineComponent({\r\n props: {\r\n text: {\r\n type: String,\r\n required: true\r\n }\r\n },\r\n\r\n setup(props) {\r\n\r\n return () => {\r\n return (\r\n {props.text}
\r\n );\r\n };\r\n }\r\n});\r\n\r\nexport const DialogBody = defineComponent({\r\n setup(_, { slots }) {\r\n\r\n return () => {\r\n return (\r\n \r\n { slots.default && slots.default() }\r\n
\r\n );\r\n };\r\n }\r\n});\r\n\r\nexport const DialogButtons = defineComponent({\r\n setup(_, { slots }) {\r\n\r\n return () => {\r\n return (\r\n \r\n { slots.default && slots.default() }\r\n
\r\n );\r\n };\r\n }\r\n});\r\n","import { defineComponent, PropType } from 'vue';\r\nimport {\r\n Dialog,\r\n DialogHeader,\r\n DialogBody,\r\n DialogButtons\r\n} from './Dialog';\r\n\r\nexport type ConfirmOptions = {\r\n text: string;\r\n action(): void;\r\n};\r\n\r\nexport type DeclineOptions = {\r\n text?: string;\r\n action(): void;\r\n};\r\n\r\nexport const ConfirmationDialog = defineComponent({\r\n props: {\r\n title: {\r\n type: String,\r\n required: true\r\n },\r\n confirm: {\r\n type: Object as PropType,\r\n required: true\r\n },\r\n decline: {\r\n type: Object as PropType,\r\n required: true\r\n },\r\n showClose: {\r\n type: Boolean,\r\n required: false\r\n }\r\n },\r\n\r\n setup(props, {slots}) {\r\n\r\n return () => (\r\n \r\n );\r\n }\r\n});","import { defineComponent, ref } from 'vue';\r\nimport { Checkbox } from '@/components/forms/Checkbox';\r\nimport { TryOutForm} from '@/components/forms/TryOut';\r\nimport { ConfirmationDialog } from '@/components/ConfirmationDialog';\r\nimport { useActionBar, ActionBar, provideActionBar } from '@/components/ActionBar';\r\n\r\nexport default defineComponent({\r\n setup() {\r\n const isEnabled = ref(false);\r\n\r\n const alwaysFalse = ref(false);\r\n\r\n const showDialog = ref(false);\r\n\r\n const { actionBar, actions} = useActionBar();\r\n provideActionBar(actionBar);\r\n\r\n return () => (\r\n \r\n
\r\n This is an about page
\r\n \r\n\r\n isEnabled.value = x}\r\n >\r\n \r\n\r\n {isEnabled.value ? \"Enabled\" : \"Not\"}\r\n\r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n \r\n\r\n {alwaysFalse.value = x; setTimeout(() => alwaysFalse.value = false, 0)}}\r\n >\r\n\r\n \r\n\r\n { showDialog.value &&\r\n {\r\n showDialog.value = false\r\n }\r\n }}\r\n decline={{\r\n action: () => {\r\n showDialog.value = false\r\n }\r\n }}\r\n >\r\n \r\n \r\n \r\n }\r\n \r\n );\r\n }\r\n });","import { defineComponent, PropType } from 'vue';\r\n\r\ntype Something = {\r\n id: number;\r\n text: string;\r\n}\r\n\r\nexport default defineComponent({\r\n props: {\r\n msg: String,\r\n items: Array as PropType\r\n },\r\n setup(props) {\r\n return () => (\r\n \r\n
{props.msg}
\r\n
\r\n For a guide and recipes on how to configure / customize this project,
\r\n check out the\r\n vue-cli documentation.\r\n
\r\n
Installed CLI Plugins
\r\n
\r\n
Essential Links
\r\n
\r\n
Ecosystem
\r\n
\r\n
\r\n );\r\n }\r\n});\r\n","import { ref, defineComponent } from \"vue\";\r\nexport default defineComponent({\r\n props: {\r\n seed: Number \r\n },\r\n\r\n setup(props) {\r\n const count = ref(props.seed || 0);\r\n const increase = () => {\r\n count.value++\r\n };\r\n\r\n return () => (\r\n \r\n \r\n
\r\n );\r\n }\r\n});\r\n\r\n","import HellowWorld from '@/components/HelloWorld';\r\nimport Counter from '@/components/Counter';\r\nimport { defineComponent, ref } from 'vue';\r\nimport logoUrl from \"@/assets/logo.png\";\r\n\r\nexport default defineComponent({\r\n setup() {\r\n const msg = ref(\"Hello via props\");\r\n const change = () => {\r\n msg.value = \"abc\";\r\n };\r\n\r\n return () => (\r\n \r\n

\r\n
\r\n
\r\n \r\n \r\n );\r\n }\r\n});","import { UnreachableValueError } from '@/components/misc';\r\nimport { reactive } from 'vue';\r\n\r\nexport type ModelValue = {\r\n value: TValue;\r\n validationMessage?: string | undefined;\r\n wasTouched?: boolean | undefined;\r\n};\r\n\r\nexport function isModelValue(value: unknown): value is ModelValue {\r\n return value\r\n && typeof value === \"object\"\r\n && !Array.isArray(value)\r\n && \"value\" in value;\r\n}\r\n\r\nexport type ModelValueChanged = Omit, \"validationMessage\">;\r\n\r\nexport type WrappedValue =\r\n TValue extends string\r\n ? string\r\n :\r\n TValue extends boolean\r\n ? boolean\r\n : \r\n TValue extends number\r\n ? number\r\n :\r\n TValue extends Array\r\n ? ModelValue>[]\r\n :\r\n TValue extends {}\r\n ? {\r\n [TProperty in keyof TValue]: ModelValue>;\r\n }\r\n :\r\n never;\r\n\r\nexport function wrapInModelValue(\r\n value: TValue\r\n): ModelValue> {\r\n return {\r\n value: wrapValue(value)\r\n };\r\n}\r\n\r\nexport function wrapValue(value: TValue): WrappedValue {\r\n if (Array.isArray(value)) {\r\n return value.map((x) => wrapInModelValue(x)) as WrappedValue;\r\n }\r\n\r\n if (typeof value === \"object\"\r\n && value !== null\r\n && value !== undefined\r\n ){\r\n const wrappedObject = {};\r\n for (const property in value)\r\n {\r\n (wrappedObject as any)[property] = wrapInModelValue(value[property]);\r\n }\r\n\r\n return wrappedObject as WrappedValue;\r\n }\r\n\r\n return value as any;\r\n}\r\n\r\nexport type UnwrappedValue = \r\n TValue extends ModelValue\r\n ? string\r\n :\r\n TValue extends ModelValue\r\n ? boolean\r\n :\r\n TValue extends ModelValue\r\n ? number\r\n :\r\n TValue extends Array\r\n ? UnwrappedValue[]\r\n :\r\n TValue extends ModelValue>\r\n ? UnwrappedValue[]\r\n :\r\n TValue extends ModelValue<{}>\r\n ? {\r\n [TProperty in keyof TValue[\"value\"]]: UnwrappedValue;\r\n }\r\n :\r\n TValue extends {}\r\n ? {\r\n [TProperty in keyof TValue]: UnwrappedValue;\r\n }\r\n :\r\n TValue;\r\n\r\nexport function unwrapModelValue(value: TValue): UnwrappedValue {\r\n if (isModelValue(value)){\r\n return unwrapValue(value.value as any);\r\n }\r\n\r\n // TODO WJG should we throw here?\r\n return value as UnwrappedValue;\r\n}\r\n\r\nexport function unwrapValue(value: TValue): UnwrappedValue {\r\n if (Array.isArray(value)) {\r\n return value.map((x) => unwrapModelValue(x)) as UnwrappedValue;\r\n }\r\n\r\n if (typeof value === \"object\"\r\n && value !== null\r\n && value !== undefined\r\n ){\r\n const unWrappedObject = {};\r\n for (const property in value)\r\n {\r\n (unWrappedObject as any)[property] = unwrapModelValue(value[property]);\r\n }\r\n\r\n return unWrappedObject as UnwrappedValue;\r\n }\r\n\r\n return value as UnwrappedValue;\r\n}\r\n\r\nexport interface IValidationError {\r\n readonly path: string;\r\n readonly message: string;\r\n}\r\n\r\nexport function simpleValidationError(message: string): IValidationError {\r\n return {\r\n message,\r\n path: \"\"\r\n };\r\n}\r\n\r\nexport class PrefixedValidationError implements IValidationError\r\n{\r\n private readonly _prefix: string;\r\n private readonly _error: IValidationError;\r\n\r\n public get path(): string {\r\n return this._prefix + this._error.path;\r\n }\r\n\r\n public get message(): string {\r\n return this._error.message;\r\n }\r\n\r\n constructor(prefix: string, error: IValidationError)\r\n {\r\n this._prefix = prefix;\r\n this._error = error;\r\n }\r\n}\r\n\r\nexport interface IValidationContext\r\n{\r\n readonly rootContext: IValidationContext;\r\n readonly parentContext: IValidationContext | null;\r\n readonly childContexts: readonly IValidationContext[];\r\n readonly path: string;\r\n readonly isInvalid: boolean;\r\n\r\n readonly errors: readonly IValidationError[];\r\n}\r\n\r\nexport interface IWritableValidationContext extends IValidationContext {\r\n add(error: IValidationError): void;\r\n}\r\n\r\nexport class ValidationContext implements IWritableValidationContext {\r\n\r\n private readonly _childContexts: IValidationContext[];\r\n private readonly _errors: IValidationError[];\r\n private _isMarkedInvalid: boolean;\r\n\r\n public readonly rootContext: IValidationContext;\r\n public readonly parentContext: IValidationContext | null;\r\n\r\n public readonly pathSegment: string;\r\n public readonly value: TValue;\r\n\r\n public get path(): string {\r\n return this.parentContext\r\n ? this.parentContext.path + this.pathSegment\r\n : this.pathSegment;\r\n }\r\n\r\n public get childContexts(): readonly IValidationContext[] {\r\n return this._childContexts;\r\n }\r\n\r\n public get errors(): readonly IValidationError[] {\r\n const result: IValidationError[] = [...this._errors];\r\n\r\n const pathSegment: string = this.pathSegment;\r\n for (const childContext of this._childContexts)\r\n {\r\n const childErrors: readonly IValidationError[] = childContext.errors\r\n .map(x => new PrefixedValidationError(pathSegment, x));\r\n result.push(...childErrors);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n public get isInvalid(): boolean {\r\n return this._isMarkedInvalid || this.childContexts.some(x => x.isInvalid);\r\n }\r\n\r\n private constructor(\r\n parentContext: IValidationContext | null,\r\n pathSegment: string,\r\n value: TValue\r\n ) {\r\n this.parentContext = parentContext;\r\n this.rootContext = parentContext?.rootContext || this;\r\n this.value = value;\r\n this.pathSegment = pathSegment;\r\n this._errors = [];\r\n this._childContexts = [];\r\n this._isMarkedInvalid = false;\r\n }\r\n\r\n public add(error: IValidationError)\r\n {\r\n this.markInvalid();\r\n this._errors.push(new PrefixedValidationError(this.pathSegment, error));\r\n }\r\n\r\n public markInvalid()\r\n {\r\n this._isMarkedInvalid = true;\r\n }\r\n\r\n public static createRoot(value: TValue): ValidationContext\r\n {\r\n return new ValidationContext(null, \"\", value);\r\n }\r\n\r\n public createChildContext(pathSegment: string, value: TOtherValue): ValidationContext\r\n {\r\n const childContext = new ValidationContext(this, pathSegment, value);\r\n this._childContexts.push(childContext);\r\n return childContext;\r\n }\r\n}\r\n\r\nexport type IValidator = (context: ValidationContext) => void;\r\n\r\nexport function validatorCollection (\r\n { stopAfterInvalidResult }: { stopAfterInvalidResult: boolean; },\r\n ...validators: IValidator[]\r\n): IValidator {\r\n\r\n return (context) => {\r\n for (const validator of validators) {\r\n validator(context);\r\n if (stopAfterInvalidResult && context.isInvalid) {\r\n return;\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport type PropertyValidators = {\r\n [TProperty in keyof TObject]?: IValidator\r\n};\r\n\r\n\r\nexport function forObject(\r\n ...validators: IValidator[]\r\n): IValidator {\r\n return validatorCollection(\r\n { stopAfterInvalidResult: false },\r\n ...validators\r\n );\r\n}\r\n\r\nexport function forProperties(\r\n propertyValidators: PropertyValidators\r\n): IValidator {\r\n return (context) => {\r\n const value: TObject = context.value || {};\r\n\r\n // TypeScript doesn't have a manner to go over the key/values of an object\r\n // in a typesafe manner. Only in the type definition it has this\r\n const propertyNameContainingValidator: string[] = Object.getOwnPropertyNames(propertyValidators);\r\n for (const propertyName of propertyNameContainingValidator) {\r\n \r\n const validator: IValidator = (propertyValidators as any)[propertyName];\r\n\r\n let propertyValue: unknown = undefined;\r\n if (propertyName in value) {\r\n propertyValue = (value as any)[propertyName];\r\n }\r\n\r\n const childContextPathSegment = context.path.length > 0\r\n ? \".\" + propertyName\r\n : propertyName;\r\n\r\n const childContext: ValidationContext = context\r\n .createChildContext(childContextPathSegment, propertyValue);\r\n\r\n validator(childContext);\r\n }\r\n };\r\n}\r\n\r\nexport function forScalar(\r\n ...validators: IValidator[]\r\n): IValidator {\r\n return validatorCollection(\r\n { stopAfterInvalidResult: true },\r\n ...validators\r\n );\r\n}\r\n\r\nexport function forCollection(\r\n ...validators: IValidator[]\r\n): IValidator {\r\n\r\n return validatorCollection(\r\n { stopAfterInvalidResult: false },\r\n ...validators\r\n );\r\n}\r\n\r\nexport function forItems(\r\n ...validators: IValidator[]\r\n): IValidator {\r\n\r\n const validator: IValidator = validatorCollection(\r\n { stopAfterInvalidResult: false},\r\n ...validators\r\n );\r\n\r\n return (context) => {\r\n const value: TArrayItem[] = context.value;\r\n let index: number = 0;\r\n for (const item of value) {\r\n const itemContext: ValidationContext = context\r\n .createChildContext(`[${index}]`, item);\r\n validator(itemContext);\r\n index++;\r\n }\r\n };\r\n}\r\n\r\nexport const notEmpty: IValidator = (context) => {\r\n const value: string = context.value;\r\n if (!value){\r\n context.add(simpleValidationError(\"Cannot be empty\"));\r\n }\r\n};\r\n\r\nexport function equals(valueToMatch: string): IValidator {\r\n return (context) => {\r\n const value: string = context.value;\r\n if (value !== valueToMatch){\r\n context.add(simpleValidationError(`Does not match '${valueToMatch}'`));\r\n }\r\n };\r\n}\r\n\r\nexport function maxLength(maxLength: number): IValidator<{ length: number; }> {\r\n\r\n return (context) => {\r\n const value: { length: number; } = context.value;\r\n if (value.length > maxLength) {\r\n context.add(simpleValidationError(`Cannot contain more then '${maxLength}' entries`));\r\n }\r\n }\r\n}\r\n\r\nexport function when(\r\n predicate: (value: TValue) => boolean,\r\n validator: IValidator\r\n): IValidator {\r\n \r\n return (context) => {\r\n if (predicate(context.value)) {\r\n validator(context);\r\n }\r\n }\r\n}\r\n\r\ntype TypeGuard = (value: TOriginal) => value is TCasted;\r\n\r\nexport function whenType(\r\n guard: TypeGuard,\r\n validator: IValidator\r\n): IValidator {\r\n\r\n return (context) => {\r\n const value: TValue = context.value;\r\n if (guard(value)) {\r\n const castedContext = context.createChildContext(\"\", value);\r\n validator(castedContext);\r\n }\r\n }\r\n}\r\n\r\nexport type ValidationResult = {\r\n isInvalid: false;\r\n}\r\n |\r\n{\r\n isInvalid: true;\r\n errors: readonly IValidationError[];\r\n}\r\n\r\nexport function validate(\r\n value: TValue,\r\n validator: IValidator\r\n): ValidationResult {\r\n const context = ValidationContext.createRoot(value);\r\n validator(context);\r\n\r\n if (context.isInvalid) {\r\n return {\r\n isInvalid: context.isInvalid,\r\n errors: context.errors\r\n };\r\n }\r\n\r\n return {\r\n isInvalid: false\r\n };\r\n}\r\n\r\n\r\nconst enum PathSegmentKind {\r\n Property = 1,\r\n Indexer = 2\r\n}\r\n\r\ntype PathSegment = { kind: PathSegmentKind.Property, value: string }\r\n | { kind: PathSegmentKind.Indexer, value: string };\r\n\r\n\r\nfunction ensureValidAutoClosingSegment(segment: PathSegment, processedPath: string) {\r\n if (!segment) {\r\n return;\r\n }\r\n\r\n switch (segment.kind)\r\n {\r\n case PathSegmentKind.Property:\r\n if (!segment.value) {\r\n throw new Error(`No property name is set. Processed: '${processedPath}'`);\r\n }\r\n break;\r\n case PathSegmentKind.Indexer:\r\n throw new Error(`Indexer is not an auto closing segment. Processed: '${processedPath}'`);\r\n break;\r\n default:\r\n throw new UnreachableValueError(segment);\r\n }\r\n}\r\n\r\nexport function parsePath(path: string): string[] {\r\n const result: string[] = [];\r\n let currentSegment: PathSegment | null = null;\r\n \r\n let processedPath = \"\";\r\n for (const char of path) {\r\n processedPath += char;\r\n if (char === \".\") {\r\n if (currentSegment) {\r\n ensureValidAutoClosingSegment(currentSegment, processedPath);\r\n result.push(currentSegment.value);\r\n }\r\n\r\n currentSegment = { kind: PathSegmentKind.Property, value: \"\" };\r\n } else if (char === \"[\") {\r\n if (currentSegment) {\r\n ensureValidAutoClosingSegment(currentSegment, processedPath);\r\n result.push(currentSegment.value);\r\n }\r\n\r\n currentSegment = { kind: PathSegmentKind.Indexer, value: \"\" };\r\n } else if (char === \"]\") {\r\n if (!currentSegment || currentSegment.kind !== PathSegmentKind.Indexer) {\r\n throw new Error(`No indexer segment to self close. Processed: '${processedPath}'`);\r\n }\r\n\r\n if (!currentSegment.value) {\r\n throw new Error(`No indexer value is set. Processed: '${processedPath}'`);\r\n }\r\n\r\n result.push(currentSegment.value);\r\n currentSegment = null;\r\n } else {\r\n if (!currentSegment) {\r\n currentSegment = { kind: PathSegmentKind.Property, value: \"\" };\r\n }\r\n\r\n switch (currentSegment.kind)\r\n {\r\n case PathSegmentKind.Property:\r\n currentSegment.value += char;\r\n break;\r\n case PathSegmentKind.Indexer:\r\n currentSegment.value += char;\r\n break; \r\n default:\r\n throw new UnreachableValueError(currentSegment);\r\n }\r\n }\r\n }\r\n\r\n if (currentSegment) {\r\n ensureValidAutoClosingSegment(currentSegment, processedPath);\r\n result.push(currentSegment.value);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport function getByPath(\r\n object: object | object[],\r\n path: string\r\n): unknown {\r\n const segments = parsePath(path);\r\n let currentObject: unknown = object;\r\n for (const segment of segments) {\r\n if (isModelValue(currentObject)) {\r\n currentObject = currentObject.value;\r\n }\r\n\r\n if (typeof currentObject !== \"object\" || !currentObject) {\r\n throw new Error(`Cannot index into: '${currentObject}'`);\r\n }\r\n currentObject = (currentObject as any)[segment];\r\n }\r\n\r\n return currentObject;\r\n}\r\n\r\nexport function processValidationError(\r\n state: object | object[],\r\n error: IValidationError,\r\n { ignoreUntouched }: { ignoreUntouched: boolean} = { ignoreUntouched: true }\r\n): boolean {\r\n const { path, message} = error;\r\n if (!path || path === \"\") {\r\n return false;\r\n }\r\n \r\n const object: unknown = getByPath(state, path);\r\n if (isModelValue(object)) {\r\n if (object.wasTouched || !ignoreUntouched) {\r\n object.validationMessage = message;\r\n }\r\n\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n}\r\n\r\nexport function hasAnyValidationMessages(\r\n value: unknown\r\n): boolean {\r\n if (!value) {\r\n return false;\r\n }\r\n\r\n if (isModelValue(value)) {\r\n if (value.validationMessage) {\r\n return true;\r\n }\r\n return hasAnyValidationMessages(value.value);\r\n } else if (Array.isArray(value)) {\r\n for (const item of value) {\r\n const itemHasAnyValidationMessages: boolean = hasAnyValidationMessages(item);\r\n if (itemHasAnyValidationMessages) {\r\n return true;\r\n }\r\n }\r\n } else if (typeof value === \"object\"\r\n && value !== null\r\n && value !== undefined\r\n ) {\r\n for (const property in value) {\r\n const itemHasAnyValidationMessages: boolean = hasAnyValidationMessages((value as any)[property]);\r\n if (itemHasAnyValidationMessages) {\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\nexport function useModelValidation(\r\n model: TModel,\r\n validator?: IValidator\r\n) {\r\n const modelState = reactive(\r\n wrapValue(model)\r\n ) as WrappedValue;\r\n\r\n function getModel(): TModel {\r\n return unwrapValue(modelState) as any as TModel;\r\n }\r\n\r\n function validateModel(\r\n { ignoreUntouched }: { ignoreUntouched: boolean} = { ignoreUntouched: true}\r\n ) {\r\n if (!validator) {\r\n return true;\r\n }\r\n \r\n const modelToValidate: TModel = getModel();\r\n const validationResult: ValidationResult = validate(modelToValidate, validator);\r\n if (!validationResult.isInvalid) {\r\n return true;\r\n }\r\n\r\n for (const error of validationResult.errors) {\r\n if (!processValidationError(modelState, error, { ignoreUntouched })) {\r\n console.error(`Was not able to process error for path '${error.path}'`);\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n function patchModel(patchState: Partial>) {\r\n for (const property in patchState) {\r\n const propertyValue = patchState[property]; \r\n if (propertyValue) {\r\n (modelState as any)[property] = propertyValue;\r\n }\r\n }\r\n\r\n validateModel();\r\n }\r\n\r\n return {\r\n modelState,\r\n patchModel,\r\n getModel,\r\n isValid: validateModel\r\n };\r\n}","import { defineComponent } from \"vue\";\r\n\r\nexport const StateViewer = defineComponent({\r\n\r\n props: {\r\n state: {\r\n required: true\r\n }\r\n },\r\n\r\n setup(props) {\r\n\r\n return () => {\r\n\r\n return (\r\n {JSON.stringify(props.state, null, 4)}
\r\n );\r\n };\r\n }\r\n});","const ID_PREFIX: string =\"__id__\";\r\nlet idCounter: number = 1;\r\n\r\nexport function generateId(): string {\r\n return ID_PREFIX + ++idCounter;\r\n}\r\n\r\nexport type GeneratedIds = Record;\r\n\r\nexport function generateIds(\r\n object: TObject\r\n): GeneratedIds {\r\n const result: Partial> = {};\r\n for (const propertyName in object) {\r\n result[propertyName] = generateId();\r\n }\r\n return result as Record;\r\n}\r\n\r\n","import { defineComponent, computed, PropType, ref } from 'vue';\r\nimport { \r\n IValidator,\r\n forProperties,\r\n forScalar,\r\n notEmpty,\r\n equals,\r\n forCollection,\r\n maxLength,\r\n forItems,\r\n ModelValue,\r\n ModelValueChanged,\r\n hasAnyValidationMessages,\r\n useModelValidation,\r\n WrappedValue,\r\n wrapInModelValue\r\n} from '@/infrastructure/validation';\r\nimport { ValidationMessage, FormItem, Form } from '@/components/forms/TryOut';\r\nimport { StateViewer } from '@/components/StateViewer';\r\nimport { generateIds } from '@/infrastructure/utils';\r\nimport { BusyIndicatorContainer } from '@/components/BusyIndicator';\r\nimport { useResizeObserver } from '@/infrastructure/sizing';\r\nimport { SomeBar } from '@/components/ActionBar';\r\n\r\ntype SectionModel = {\r\n a: string;\r\n b: string;\r\n};\r\n\r\ntype Model = {\r\n upn: string;\r\n firstName: string;\r\n lastName: string;\r\n section: SectionModel;\r\n array: string[];\r\n};\r\n\r\nconst validator: IValidator = forProperties(\r\n {\r\n upn: notEmpty,\r\n firstName: forScalar(\r\n notEmpty,\r\n equals(\"123\")\r\n ),\r\n lastName: notEmpty,\r\n section: forProperties({\r\n a: notEmpty,\r\n b: notEmpty\r\n }),\r\n array: forCollection(\r\n maxLength(3),\r\n forItems(\r\n notEmpty\r\n )\r\n )\r\n }\r\n);\r\n\r\nexport const TestPage = defineComponent({\r\n\r\n setup() {\r\n const defaultModel: Model = {\r\n upn: \"\",\r\n firstName: \"\",\r\n lastName: \"\",\r\n section: {\r\n a: \"\",\r\n b: \"\"\r\n },\r\n array: []\r\n };\r\n\r\n const { modelState, patchModel } = useModelValidation(defaultModel, validator);\r\n\r\n const hasErrors = computed(() => hasAnyValidationMessages(modelState));\r\n\r\n const onChange = (patchState: Partial>) => {\r\n patchModel(patchState);\r\n };\r\n\r\n const ids = generateIds(defaultModel);\r\n\r\n const isBusy = ref(false);\r\n\r\n const { element, size } = useResizeObserver();\r\n\r\n return () => {\r\n\r\n const {\r\n upn,\r\n firstName,\r\n lastName,\r\n section,\r\n array\r\n } = modelState;\r\n\r\n return (\r\n \r\n
\r\n
\r\n Width: {size.width}\r\n Height: {size.height}\r\n
\r\n
\r\n
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n
\r\n
\r\n );\r\n }\r\n }\r\n});\r\n\r\n\r\nexport const FormTextInput = defineComponent({\r\n props: {\r\n id: String,\r\n value: {\r\n type: Object as PropType>,\r\n required: true\r\n },\r\n onChange: Function as PropType<(value: ModelValueChanged) => void>,\r\n autofocus: {\r\n type: Boolean,\r\n required: false\r\n }\r\n },\r\n\r\n setup(props) {\r\n const onChange = (args: Event) => {\r\n if (props.onChange) {\r\n props.onChange({\r\n value: (args.target as HTMLInputElement).value,\r\n wasTouched: true\r\n });\r\n }\r\n };\r\n\r\n return () => {\r\n const { value, validationMessage } = props.value;\r\n let classes: string = \"form__input\";\r\n if (validationMessage) {\r\n classes += \" form__input--error\";\r\n }\r\n return (\r\n <>\r\n {\r\n if (props.autofocus && input) {\r\n (input as HTMLInputElement).focus();\r\n }\r\n }}\r\n >\r\n \r\n \r\n >\r\n );\r\n }\r\n }\r\n});\r\n\r\nexport const SectionTest = defineComponent({\r\n props: {\r\n value: {\r\n type: Object as PropType>>,\r\n required: true\r\n },\r\n onChange: Function as PropType<(value: ModelValueChanged>) => void>\r\n },\r\n\r\n setup(props) {\r\n\r\n const ids = generateIds(props.value.value);\r\n\r\n const { element, size } = useResizeObserver();\r\n\r\n const onChange = (patchedValue: Partial>) => {\r\n if (props.onChange) {\r\n const newValue = {...props.value.value, ...patchedValue};\r\n props.onChange({ value: newValue, wasTouched: props.value.wasTouched });\r\n }\r\n };\r\n\r\n return () => {\r\n const { \r\n value: {\r\n value,\r\n validationMessage\r\n }\r\n } = props;\r\n\r\n const { a, b } = value;\r\n \r\n return (\r\n <>\r\n \r\n\r\n \r\n \r\n Width: {size.width} Height: {size.height}\r\n
\r\n onChange({ a: changedValue })}\r\n value={a}\r\n >\r\n \r\n \r\n\r\n \r\n onChange({ b: changedValue })}\r\n value={b}\r\n >\r\n \r\n \r\n >\r\n );\r\n };\r\n }\r\n});","import {\r\n defineComponent,\r\n PropType,\r\n ref,\r\n reactive,\r\n VNode,\r\n onBeforeUnmount,\r\n CSSProperties\r\n} from 'vue';\r\n\r\nexport type Coordinate = {\r\n x: number;\r\n y: number;\r\n};\r\n\r\nexport type DragCallbackArgs = {\r\n movement: Coordinate;\r\n offset: Coordinate;\r\n};\r\n\r\nexport type DragCallback = (args: DragCallbackArgs) => void;\r\n\r\nconst OVERFLOW_REGEX = /(auto|scroll)/;\r\n\r\nfunction findNearestScrollContainer(element: HTMLElement) {\r\n while (element.parentElement) {\r\n const parent = element.parentNode as HTMLElement;\r\n \r\n const computedStyles: CSSStyleDeclaration = window.getComputedStyle(parent);\r\n if (OVERFLOW_REGEX.test(computedStyles.overflow + computedStyles.overflowX + computedStyles.overflowY)) {\r\n return parent;\r\n }\r\n\r\n element = parent;\r\n }\r\n return document.scrollingElement as HTMLElement;\r\n}\r\n\r\nconst SCROLL_SENSITIVENESS = 20;\r\nconst SCROLL_SPEED = 20;\r\n\r\nlet pointerDownHandled: boolean = false;\r\n\r\nexport const Draggable = defineComponent({\r\n props :{\r\n onStart: {\r\n type: Function as PropType\r\n },\r\n onDrag: {\r\n type: Function as PropType\r\n },\r\n onStop: {\r\n type: Function as PropType\r\n }\r\n },\r\n\r\n setup(props, { slots }) {\r\n const isDragging = ref(false);\r\n const isPointerDown = ref(false);\r\n const preventClick = ref(false);\r\n const pointerDownOffset = reactive({\r\n x: -1,\r\n y: -1\r\n } as Coordinate);\r\n\r\n const startOffset = reactive({\r\n x: -1,\r\n y: -1\r\n } as Coordinate);\r\n\r\n const startScrollOffset = reactive({\r\n x: -1,\r\n y: -1\r\n } as Coordinate);\r\n const scrollContainer = ref(null);\r\n\r\n const pointerIdentifier = ref(undefined);\r\n\r\n const hasMovedEnough = ({x, y}: {x: number; y: number; }) => {\r\n return Math.abs(x) >= 5 || Math.abs(y) >= 5;\r\n };\r\n\r\n function getTouch(args: TouchEvent): Touch | undefined {\r\n for (const touch of args.changedTouches) {\r\n if (touch.identifier === pointerIdentifier.value) {\r\n return touch;\r\n }\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n function getMovement(args: MouseEvent | Touch): Coordinate {\r\n const movement = {\r\n x: args.pageX - pointerDownOffset.x,\r\n y: args.pageY - pointerDownOffset.y\r\n };\r\n\r\n if (scrollContainer.value && scrollContainer.value !== document.scrollingElement) {\r\n movement.y += scrollContainer.value.scrollTop - startScrollOffset.y;\r\n movement.x += scrollContainer.value.scrollLeft - startScrollOffset.x;\r\n }\r\n\r\n return movement;\r\n }\r\n\r\n function handlePointerDown(args: UIEvent, pointerArgs: MouseEvent | Touch) {\r\n if (pointerDownHandled) {\r\n return;\r\n }\r\n pointerDownHandled = true;\r\n if (isDragging.value) {\r\n return;\r\n }\r\n\r\n if (\"identifier\" in pointerArgs) {\r\n pointerIdentifier.value = pointerArgs.identifier;\r\n }\r\n\r\n const element = args.currentTarget as HTMLElement;\r\n scrollContainer.value = findNearestScrollContainer(element);\r\n\r\n startOffset.x = element.offsetLeft;\r\n startOffset.y = element.offsetTop;\r\n\r\n if (scrollContainer.value) {\r\n startScrollOffset.x = scrollContainer.value.scrollLeft;\r\n startScrollOffset.y = scrollContainer.value.scrollTop;\r\n }\r\n\r\n pointerDownOffset.x = pointerArgs.pageX;\r\n pointerDownOffset.y = pointerArgs.pageY;\r\n\r\n isPointerDown.value = true;\r\n }\r\n\r\n function onMouseDown(args: MouseEvent) {\r\n if (args.button !== 0) {\r\n return;\r\n }\r\n args.preventDefault();\r\n handlePointerDown(args, args);\r\n attachToPostMouseDownEvents();\r\n }\r\n\r\n function handlePointerMove(args: MouseEvent | Touch) {\r\n if (!isPointerDown.value) {\r\n return;\r\n }\r\n\r\n const movement = getMovement(args);\r\n\r\n if (!isDragging.value) {\r\n if (hasMovedEnough(movement)) {\r\n preventClick.value = true;\r\n isDragging.value = true;\r\n const focusedElement = document.activeElement;\r\n if (focusedElement && \"blur\" in focusedElement) {\r\n (focusedElement as HTMLElement).blur();\r\n }\r\n \r\n if (props.onStart) {\r\n props.onStart({ movement, offset: startOffset });\r\n }\r\n }\r\n }\r\n\r\n if (isDragging.value) {\r\n if (scrollContainer.value) {\r\n const scroller = scrollContainer.value;\r\n\r\n if (scroller !== document.scrollingElement) {\r\n if (args.pageY - scroller.offsetTop < SCROLL_SENSITIVENESS) {\r\n scroller.scrollTop = scroller.scrollTop - SCROLL_SPEED;\r\n } else if ((scroller.offsetTop + scroller.clientHeight) - args.pageY < SCROLL_SENSITIVENESS) {\r\n scroller.scrollTop = scroller.scrollTop + SCROLL_SPEED;\r\n }\r\n\r\n if (args.pageX - scroller.offsetLeft < SCROLL_SENSITIVENESS) {\r\n scroller.scrollLeft = scroller.scrollLeft - SCROLL_SPEED;\r\n } else if ((scroller.offsetLeft + scroller.clientWidth) - args.pageX < SCROLL_SENSITIVENESS) {\r\n scroller.scrollLeft = scroller.scrollLeft + SCROLL_SPEED;\r\n }\r\n } else {\r\n if (args.pageY - scroller.scrollTop < SCROLL_SENSITIVENESS) {\r\n scroller.scrollTop = scroller.scrollTop - SCROLL_SPEED;\r\n } else if (scroller.clientHeight - (args.pageY - scroller.scrollTop) < SCROLL_SENSITIVENESS) {\r\n scroller.scrollTop = scroller.scrollTop + SCROLL_SPEED;\r\n }\r\n\r\n if (args.pageX - scroller.scrollLeft < SCROLL_SENSITIVENESS) {\r\n scroller.scrollLeft = scroller.scrollLeft - SCROLL_SPEED;\r\n } else if (scroller.clientWidth - (args.pageX - scroller.scrollLeft) < SCROLL_SENSITIVENESS) {\r\n scroller.scrollLeft = scroller.scrollLeft + SCROLL_SPEED;\r\n }\r\n }\r\n }\r\n\r\n if (props.onDrag) {\r\n props.onDrag({ movement, offset: startOffset });\r\n }\r\n }\r\n }\r\n\r\n function onMouseMove(args: MouseEvent) {\r\n if (isDragging.value) {\r\n args.preventDefault();\r\n }\r\n handlePointerMove(args);\r\n }\r\n\r\n function handlePointerUp(args: MouseEvent | Touch) {\r\n isPointerDown.value = false;\r\n\r\n if (isDragging.value) {\r\n const movement = getMovement(args);\r\n\r\n if (props.onStop) {\r\n props.onStop({ movement, offset: startOffset });\r\n }\r\n }\r\n \r\n isDragging.value = false;\r\n startOffset.x = -1;\r\n startOffset.y = -1;\r\n startScrollOffset.x = -1;\r\n startScrollOffset.y = -1;\r\n pointerDownOffset.x = -1;\r\n pointerDownOffset.y = -1;\r\n pointerIdentifier.value = undefined;\r\n scrollContainer.value = null;\r\n\r\n setTimeout(() => preventClick.value = false);\r\n pointerDownHandled = false;\r\n }\r\n\r\n function onMouseUp(args: MouseEvent) {\r\n handlePointerUp(args);\r\n detachFromPostMouseDownEvents();\r\n }\r\n\r\n function onTouchStart(args: TouchEvent) {\r\n handlePointerDown(args, args.changedTouches[0]);\r\n attachToPostTouchStartEvents();\r\n }\r\n\r\n function onTouchMove(args: TouchEvent) {\r\n const touch = getTouch(args);\r\n if (!touch){\r\n return;\r\n }\r\n handlePointerMove(touch);\r\n\r\n if (isDragging.value) {\r\n args.preventDefault();\r\n }\r\n }\r\n\r\n function onTouchEnd(args: TouchEvent) {\r\n const touch = getTouch(args);\r\n if (!touch){\r\n return;\r\n }\r\n handlePointerUp(touch);\r\n detachFromPostMouseDownEvents();\r\n }\r\n\r\n function attachToPostMouseDownEvents() {\r\n window.addEventListener(\"mousemove\", onMouseMove);\r\n window.addEventListener(\"mouseup\", onMouseUp);\r\n }\r\n\r\n function detachFromPostMouseDownEvents() {\r\n window.removeEventListener(\"mousemove\", onMouseMove);\r\n window.removeEventListener(\"mouseup\", onMouseUp);\r\n }\r\n\r\n function attachToPostTouchStartEvents() {\r\n // passive: false is important as chrome by default will disallow preventDefault for these \"expensive\" events\r\n // without preventDefault it might trigger the \"pull down to refresh\" gesture\r\n window.addEventListener(\"touchmove\", onTouchMove, { passive: false });\r\n window.addEventListener(\"touchend\", onTouchEnd);\r\n }\r\n\r\n function detachFromPostTouchStartEvents() {\r\n window.removeEventListener(\"touchmove\", onTouchMove);\r\n window.removeEventListener(\"touchend\", onTouchEnd);\r\n }\r\n\r\n onBeforeUnmount(() => {\r\n detachFromPostMouseDownEvents();\r\n detachFromPostTouchStartEvents();\r\n });\r\n\r\n function wrapOnClick(originalHandler: (args: MouseEvent) => void ) {\r\n\r\n return (args: MouseEvent) => {\r\n if (preventClick.value) {\r\n args.preventDefault();\r\n return;\r\n }\r\n if (originalHandler) {\r\n originalHandler(args);\r\n }\r\n };\r\n }\r\n\r\n return () => {\r\n const children: VNode[] = slots.default && slots.default() || [];\r\n\r\n if (children.length !== 1) {\r\n throw new Error(\"Should contain exactly 1 child\");\r\n }\r\n\r\n const child: VNode = children[0];\r\n child.props = child.props || {};\r\n child.props.onMousedown = onMouseDown;\r\n child.props.onTouchstart = onTouchStart;\r\n child.props.onClick = wrapOnClick(child.props.onClick);\r\n return child;\r\n };\r\n }\r\n});\r\n\r\nexport const UnmanagedDraggable = defineComponent({\r\n setup(_, { slots }) {\r\n\r\n const originalX = ref(0);\r\n const originalY = ref(0);\r\n\r\n const x = ref(originalX.value);\r\n const y = ref(originalY.value);\r\n\r\n function onStart(args: DragCallbackArgs) {\r\n x.value = originalX.value + args.movement.x;\r\n y.value = originalY.value + args.movement.y;\r\n }\r\n\r\n function onDrag(args: DragCallbackArgs) {\r\n x.value = originalX.value + args.movement.x;\r\n y.value = originalY.value + args.movement.y;\r\n }\r\n\r\n function onStop(args: DragCallbackArgs) {\r\n x.value = originalX.value + args.movement.x;\r\n y.value = originalY.value + args.movement.y;\r\n originalX.value = x.value;\r\n originalY.value = y.value;\r\n }\r\n\r\n return () => {\r\n\r\n const style: CSSProperties = {\r\n position: \"relative\",\r\n top: `${y.value}px`,\r\n left: `${x.value}px`,\r\n };\r\n\r\n const children: VNode[] = slots.default && slots.default() || [];\r\n\r\n if (children.length !== 1) {\r\n throw new Error(\"Should contain exactly 1 child\");\r\n }\r\n\r\n const child: VNode = children[0];\r\n child.props = child.props || {};\r\n child.props.style = {...child.props.style, ...style};\r\n child.dynamicProps = child.dynamicProps || [];\r\n child.dynamicProps.push(\"style\");\r\n\r\n return (\r\n \r\n {child}\r\n \r\n );\r\n };\r\n }\r\n});","import {\r\n defineComponent,\r\n PropType,\r\n reactive,\r\n computed,\r\n ref,\r\n CSSProperties\r\n} from 'vue';\r\nimport { Coordinate, DragCallbackArgs, Draggable } from './Draggable';\r\n\r\nexport const SortableList = defineComponent({\r\n props: {\r\n items: {\r\n type: Array as PropType>,\r\n required: true\r\n },\r\n template: {\r\n type: Function as PropType<(item: any, index: number) => JSX.Element>,\r\n required: true\r\n },\r\n onOrderChanged: {\r\n type: Function as PropType<(item: any, newIndex: number, oldIndex: number) => void>,\r\n required: true\r\n },\r\n keySelector: {\r\n type: Function as PropType<(item: any) => string>,\r\n required: true\r\n }\r\n },\r\n\r\n setup(props) {\r\n const dragState = reactive({\r\n indexBeingDragged: -1 as number,\r\n placeholderIndex: -1 as number,\r\n movement: { x: 0, y: 0 } as Coordinate,\r\n offset: { x: 0, y: 0} as Coordinate\r\n });\r\n\r\n const referencesRef = computed(\r\n () => props.items.map(() => ref(null))\r\n );\r\n\r\n function getPlaceholderIndex(indexBeingDragged: number, args: DragCallbackArgs): number {\r\n const references = referencesRef.value;\r\n if (references.length === 1) {\r\n return 0;\r\n }\r\n\r\n for (let i = 0; i < references.length; i++) {\r\n if (i === indexBeingDragged) {\r\n continue;\r\n }\r\n\r\n const currentElement: HTMLElement | null = references[i].value;\r\n\r\n if (!currentElement) {\r\n continue;\r\n }\r\n \r\n const topOffset: number = currentElement.offsetTop;\r\n if (args.offset.y + args.movement.y < topOffset) {\r\n return i;\r\n }\r\n }\r\n\r\n return references.length;\r\n }\r\n\r\n function onStart(index: number, args: DragCallbackArgs) {\r\n dragState.indexBeingDragged = index;\r\n dragState.placeholderIndex = getPlaceholderIndex(index, args);\r\n dragState.movement = args.movement;\r\n dragState.offset = args.offset;\r\n }\r\n\r\n function onDrag(index: number, args: DragCallbackArgs) {\r\n dragState.movement = args.movement;\r\n dragState.placeholderIndex = getPlaceholderIndex(index, args);\r\n }\r\n\r\n function onStop(index: number, args: DragCallbackArgs) {\r\n const placeholderIndex = getPlaceholderIndex(index, args);\r\n dragState.indexBeingDragged = -1;\r\n dragState.placeholderIndex = -1;\r\n dragState.movement = { x: 0, y: 0 };\r\n dragState.offset = { x: 0, y: 0 };\r\n\r\n if (index !== placeholderIndex) {\r\n const newIndex = placeholderIndex >= index\r\n ? placeholderIndex - 1\r\n : placeholderIndex; \r\n \r\n props.onOrderChanged(props.items[index], newIndex, index);\r\n }\r\n }\r\n\r\n function renderItem(index: number, item: unknown): JSX.Element {\r\n const style: CSSProperties = {\r\n padding: \"4px\",\r\n border: \"solid 1px lightgray\",\r\n marginBottom: \"4px\",\r\n backgroundColor: \"white\"\r\n };\r\n\r\n if (index === dragState.indexBeingDragged) {\r\n style.position = \"absolute\";\r\n const { offset, movement } = dragState;\r\n style.top = `${offset.y + movement.y}px`;\r\n style.left = `${offset.x + movement.x}px`;\r\n style.width = \"100%\";\r\n }\r\n\r\n return (\r\n onStart(index, args)}\r\n onDrag={(args) => onDrag(index, args)}\r\n onStop={(args) => onStop(index, args)}\r\n >\r\n {/* we should assign a key */}\r\n \r\n {props.template(item, index)}\r\n \r\n \r\n );\r\n }\r\n\r\n function renderPlaceholder(): JSX.Element {\r\n return (\r\n \r\n placeholder\r\n \r\n );\r\n }\r\n\r\n function renderItems(): JSX.Element[] {\r\n const elements: JSX.Element[] = [];\r\n const { placeholderIndex } = dragState;\r\n for (let i = 0; i < props.items.length; i++) {\r\n if (placeholderIndex === i) {\r\n elements.push(renderPlaceholder());\r\n }\r\n\r\n elements.push(renderItem(i, props.items[i]));\r\n }\r\n\r\n if (placeholderIndex === props.items.length) {\r\n elements.push(renderPlaceholder());\r\n }\r\n\r\n return elements;\r\n }\r\n\r\n return () => {\r\n return (\r\n \r\n );\r\n };\r\n }\r\n});\r\n","import { defineComponent, PropType, ref } from 'vue';\r\nimport { FormTextInput } from '../views/TestPage';\r\nimport { ModelValueChanged, ModelValue } from '@/infrastructure/validation';\r\nimport { ValidationMessage } from './forms/TryOut';\r\n\r\nexport const InlineTextEdit = defineComponent({\r\n props: {\r\n value: {\r\n type: Object as PropType>,\r\n required: true\r\n },\r\n onChange: {\r\n type: Function as PropType<(value: ModelValueChanged) => void>\r\n }\r\n },\r\n\r\n setup(props) {\r\n\r\n const isEditing = ref(false);\r\n\r\n function switchToEdit() {\r\n isEditing.value = true;\r\n }\r\n\r\n function onChange(patch: ModelValueChanged) {\r\n if (props.onChange) {\r\n props.onChange(patch);\r\n }\r\n isEditing.value = false;\r\n }\r\n\r\n return () => {\r\n if (isEditing.value) {\r\n return (\r\n \r\n );\r\n } else {\r\n return (\r\n <>\r\n {props.value.value || \"Click here\"}\r\n \r\n >\r\n );\r\n }\r\n }; \r\n }\r\n})","import {\r\n defineComponent,\r\n} from \"vue\";\r\nimport { SortableList } from '@/components/SortableList';\r\nimport { UnmanagedDraggable } from '@/components/Draggable';\r\nimport {\r\n useModelValidation,\r\n WrappedValue,\r\n ModelValue,\r\n forCollection,\r\n forProperties,\r\n notEmpty,\r\n forItems\r\n} from '@/infrastructure/validation';\r\nimport { InlineTextEdit } from '@/components/InlineEdit';\r\nimport { Checkbox } from '@/components/forms/Checkbox';\r\n\r\ntype Mailbox = {\r\n id: number | null;\r\n address: string;\r\n};\r\n\r\nconst MailList = defineComponent({\r\n setup() {\r\n\r\n const { modelState: items, patchModel } = useModelValidation(\r\n [\r\n {\r\n id: 1,\r\n address: \"one\"\r\n },\r\n {\r\n id: 2,\r\n address: \"two\"\r\n },\r\n {\r\n id: 3,\r\n address: \"three\"\r\n },\r\n {\r\n id: 4,\r\n address: \"four\"\r\n },\r\n {\r\n id: 5,\r\n address: \"five\"\r\n },\r\n {\r\n id: 6,\r\n address: \"six\"\r\n },\r\n {\r\n id: 7,\r\n address: \"seven\"\r\n },\r\n {\r\n id: 8,\r\n address: \"eight\"\r\n },\r\n {\r\n id: 9,\r\n address: \"nine\"\r\n },\r\n {\r\n id: 10,\r\n address: \"ten\"\r\n },\r\n {\r\n id: 11,\r\n address: \"eleven\"\r\n },\r\n {\r\n id: 12,\r\n address: \"twelve\"\r\n }\r\n ],\r\n forCollection(\r\n forItems(\r\n forProperties({\r\n address: notEmpty\r\n })\r\n )\r\n )\r\n );\r\n\r\n function renderItem(\r\n item: ModelValue>,\r\n index: number\r\n ): JSX.Element {\r\n return(\r\n {\r\n const itemToPatch = items[index];\r\n itemToPatch.value.address = {...patch };\r\n const arrayPatch = [];\r\n arrayPatch[index] = itemToPatch;\r\n patchModel(arrayPatch);\r\n }}\r\n />\r\n );\r\n }\r\n\r\n function onOrderChanged(_: ModelValue>, newIndex: number, oldIndex: number) {\r\n items.splice(newIndex, 0, ...items.splice(oldIndex, 1));\r\n }\r\n\r\n function keySelector(item: ModelValue>) {\r\n return item.value.id.value!.toString();\r\n }\r\n\r\n return () => {\r\n\r\n return (\r\n <>\r\n \r\n \r\n
\r\n >\r\n );\r\n };\r\n }\r\n})\r\n\r\nexport const Dragging = defineComponent({\r\n setup() {\r\n return () => {\r\n return (\r\n <>\r\n \r\n\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n >\r\n );\r\n };\r\n }\r\n});\r\n","import { RouteRecordRaw, createRouter, createWebHistory } from 'vue-router';\r\nimport about from '@/views/about';\r\nimport home from '@/views/home';\r\nimport { TestPage } from '@/views/TestPage';\r\nimport { Dragging } from '@/views/Dragging';\r\n\r\nconst routes: RouteRecordRaw[] = [\r\n {\r\n path: '/',\r\n name: 'Home',\r\n component: home\r\n },\r\n {\r\n path: '/about',\r\n name: 'About',\r\n component: about\r\n },\r\n {\r\n path: '/test-page',\r\n name: 'TestPage',\r\n component: TestPage\r\n },\r\n {\r\n path: '/dragging',\r\n name: 'Dragging',\r\n component: Dragging\r\n }\r\n];\r\n\r\nconst router = createRouter({\r\n history: createWebHistory(),\r\n routes\r\n})\r\n\r\nexport default router\r\n","import \"@/styles/reset.less\";\r\nimport \"@/styles/test.less\";\r\nimport \"@/styles/scrollbar.less\";\r\nimport { defineComponent } from 'vue';\r\nimport { RouterView, RouterLink } from 'vue-router';\r\n\r\nexport default defineComponent({\r\n setup() {\r\n\r\n return () => {\r\n \r\n return(\r\n <>\r\n \r\n \r\n Hello world
\r\n \r\n Home |\r\n About\r\n Test page\r\n Dragging\r\n
\r\n \r\n >\r\n );\r\n };\r\n }\r\n});","import { createApp } from \"vue\";\r\nimport router from './router'\r\nimport App from './app';\r\n\r\ncreateApp(App).use(router).mount('#app')\r\n","module.exports = __webpack_public_path__ + \"img/logo.82b9c7a5.png\";"],"sourceRoot":""}