@speckle/ui-components 2.18.11 → 2.18.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.cjs","sources":["../src/components/form/Button.vue","../src/components/common/text/Link.vue","../src/helpers/global/toast.ts","../src/components/global/ToastRenderer.vue","../src/helpers/global/accessibility.ts","../src/components/common/Badge.vue","../src/helpers/tailwind.ts","../src/composables/common/steps.ts","../src/components/common/steps/Number.vue","../src/components/common/steps/Bullet.vue","../src/components/common/animation/MouseIcon.vue","../src/components/common/animation/ClickIcon.vue","../src/components/common/animation/Instructional.vue","../src/components/form/CardButton.vue","../src/components/form/Checkbox.vue","../src/components/form/Radio.vue","../src/composables/form/textInput.ts","../src/components/form/TextArea.vue","../src/components/form/TextInput.vue","../src/helpers/common/validation.ts","../src/composables/layout/resize.ts","../src/composables/form/select.ts","../src/components/form/select/Base.vue","../src/components/form/select/SourceApps.vue","../src/components/form/select/Badges.vue","../src/components/form/Switch.vue","../src/components/form/ClipboardInput.vue","../src/helpers/form/input.ts","../src/composables/form/input.ts","../src/components/layout/Dialog.vue","../src/components/layout/DialogSection.vue","../src/components/layout/Disclosure.vue","../src/helpers/layout/components.ts","../src/components/layout/GridListToggle.vue","../src/composables/common/window.ts","../src/components/layout/Menu.vue","../src/components/layout/Tabs.vue","../src/components/layout/PageTabs.vue","../src/components/layout/Table.vue","../src/components/InfiniteLoading.vue","../src/components/layout/Panel.vue","../src/components/common/Alert.vue","../src/composables/common/async.ts","../src/components/form/tags/ContextManager.vue","../src/components/form/Tags.vue","../src/composables/user/avatar.ts","../src/components/user/Avatar.vue","../src/components/user/AvatarGroup.vue","../src/components/common/loading/Icon.vue","../src/components/user/AvatarEditable.vue","../src/helpers/common/error.ts","../src/helpers/form/file.ts","../src/composables/form/fileUpload.ts","../src/components/form/file-upload/Zone.vue"],"sourcesContent":["<template>\n <Component\n :is=\"to ? linkComponent : 'button'\"\n :href=\"to\"\n :to=\"to\"\n :type=\"buttonType\"\n :external=\"external\"\n :class=\"buttonClasses\"\n :disabled=\"isDisabled\"\n role=\"button\"\n @click=\"onClick\"\n >\n <Component\n :is=\"finalLeftIcon\"\n v-if=\"finalLeftIcon\"\n :class=\"`${iconClasses} ${hideText ? '' : 'mr-2'}`\"\n />\n <slot v-if=\"!hideText\">Button</slot>\n <Component\n :is=\"iconRight\"\n v-if=\"iconRight || !loading\"\n :class=\"`${iconClasses} ${hideText ? '' : 'ml-2'}`\"\n />\n </Component>\n</template>\n<script setup lang=\"ts\">\nimport { isObjectLike } from 'lodash'\nimport type { PropType } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\nimport { computed, resolveDynamicComponent } from 'vue'\nimport type { Nullable, Optional } from '@speckle/shared'\nimport { ArrowPathIcon } from '@heroicons/vue/24/solid'\nimport type { FormButtonColor, FormButtonTextColor } from '~~/src/helpers/form/button'\n\ntype FormButtonSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl'\n\nconst emit = defineEmits([\"click\"])\n\nconst props = defineProps({\n /**\n * URL to which to navigate - can be a relative (app) path or an absolute link for an external URL\n */\n to: {\n type: String as PropType<Optional<string>>,\n required: false,\n default: undefined\n },\n /**\n * Choose from one of many button sizes\n */\n size: {\n type: String as PropType<FormButtonSize>,\n default: 'base'\n },\n /**\n * If set, will make the button take up all available space horizontally\n */\n fullWidth: {\n type: Boolean,\n default: false\n },\n /**\n * Will outline the button.\n */\n outlined: {\n type: Boolean,\n default: false\n },\n /**\n * Will apply a rounded class.\n */\n rounded: {\n type: Boolean,\n default: false\n },\n /**\n * Similar to \"link\", but without an underline and possibly in different colors\n */\n text: {\n type: Boolean,\n default: false\n },\n /**\n * Will remove paddings and background. Use for links.\n */\n link: {\n type: Boolean,\n default: false\n },\n /**\n * Colors:\n * default: the default primary blue.\n * invert: for when you want to use this button on a primary background.\n * danger: for dangerous actions (e.g. deletions).\n * warning: for less dangerous actions (e.g. archival).\n */\n color: {\n type: String as PropType<FormButtonColor>,\n default: 'default'\n },\n /**\n * Text color, only used when color=secondary\n */\n textColor: {\n type: String as PropType<FormButtonTextColor>,\n default: 'default'\n },\n /**\n * Whether the target location should be forcefully treated as an external URL\n * (for relative paths this will likely cause a redirect)\n */\n external: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n /**\n * Whether to disable the button so that it can't be pressed\n */\n disabled: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n /**\n * If set, will have type set to \"submit\" to enable it to submit any parent forms\n */\n submit: {\n type: Boolean,\n default: false\n },\n /**\n * Add icon to the left from the text\n */\n iconLeft: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Add icon to the right from the text\n */\n iconRight: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Hide default slot (when you want to show icons only)\n */\n hideText: {\n type: Boolean,\n default: false\n },\n /**\n * Customize component to be used when rendering links.\n *\n * The component will try to dynamically resolve NuxtLink and RouterLink and use those, if this is set to null.\n */\n linkComponent: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Disables the button and shows a spinning loader\n */\n loading: {\n type: Boolean,\n default: false\n }\n})\n\nconst NuxtLink = resolveDynamicComponent('NuxtLink')\nconst RouterLink = resolveDynamicComponent('RouterLink')\n\nconst linkComponent = computed(() => {\n if (props.linkComponent) return props.linkComponent\n if (props.external) return 'a'\n if (isObjectLike(NuxtLink)) return NuxtLink\n if (isObjectLike(RouterLink)) return RouterLink\n return 'a'\n})\n\nconst buttonType = computed(() => {\n if (props.to) return undefined\n if (props.submit) return 'submit'\n return 'button'\n})\n\nconst isDisabled = computed(() => props.disabled || props.loading)\nconst finalLeftIcon = computed(() => (props.loading ? ArrowPathIcon : props.iconLeft))\n\nconst bgAndBorderClasses = computed(() => {\n const classParts: string[] = []\n\n classParts.push('border-2')\n if (isDisabled.value) {\n classParts.push(\n props.outlined\n ? 'border-foreground-disabled'\n : 'bg-foundation-disabled border-transparent'\n )\n } else {\n switch (props.color) {\n case 'invert':\n classParts.push(\n props.outlined\n ? 'border-foundation dark:border-foreground'\n : 'bg-foundation dark:bg-foreground border-transparent'\n )\n break\n case 'card':\n classParts.push(\n props.outlined\n ? 'border-foundation-2 shadow'\n : 'bg-foundation-2 dark:bg-foundation-2 border-foundation shadow'\n )\n break\n case 'danger':\n classParts.push(props.outlined ? 'border-danger' : 'bg-danger border-danger')\n break\n case 'secondary':\n classParts.push(\n props.outlined ? 'border-foundation' : 'bg-foundation border-foundation-2'\n )\n break\n case 'warning':\n classParts.push(props.outlined ? 'border-warning' : 'bg-warning border-warning')\n break\n case 'info':\n classParts.push(props.outlined ? 'border-info' : 'bg-info border-info')\n break\n case 'success':\n classParts.push(props.outlined ? 'border-success' : 'bg-success border-success')\n break\n case 'default':\n default:\n classParts.push(\n props.outlined\n ? 'border-primary hover:border-primary-focus'\n : 'bg-primary hover:bg-primary-focus border-transparent'\n )\n break\n }\n }\n\n return classParts.join(' ')\n})\n\nconst foregroundClasses = computed(() => {\n const classParts: string[] = []\n const hasCustomTextColor = props.textColor !== 'default'\n\n if (hasCustomTextColor && !isDisabled.value) {\n switch (props.textColor) {\n case 'primary':\n classParts.push('text-primary')\n break\n case 'warning':\n classParts.push('text-warning')\n break\n case 'success':\n classParts.push('text-success')\n break\n case 'danger':\n classParts.push('text-danger')\n break\n case 'info':\n classParts.push('text-info')\n break\n }\n }\n\n if (!props.text && !props.link) {\n if (isDisabled.value) {\n classParts.push('text-foreground-disabled')\n } else if (!hasCustomTextColor) {\n switch (props.color) {\n case 'invert':\n classParts.push(\n props.outlined ? 'text-foundation dark:text-foreground' : 'text-primary'\n )\n break\n case 'card':\n classParts.push(props.outlined ? 'text-foreground' : 'text-foreground')\n break\n case 'danger':\n classParts.push(\n props.outlined ? 'text-danger' : 'text-foundation dark:text-foreground'\n )\n break\n case 'warning':\n classParts.push(\n props.outlined ? 'text-warning' : 'text-foundation dark:text-foreground'\n )\n break\n case 'info':\n classParts.push(\n props.outlined ? 'text-info' : 'text-foundation dark:text-foreground'\n )\n break\n case 'success':\n classParts.push(\n props.outlined ? 'text-success' : 'text-foundation dark:text-foreground'\n )\n break\n case 'secondary':\n classParts.push(\n props.outlined\n ? 'text-foreground hover:text-primary'\n : 'text-foreground hover:text-primary'\n )\n break\n case 'default':\n default:\n classParts.push(\n props.outlined\n ? 'text-primary hover:text-primary-focus'\n : 'text-foundation dark:text-foreground'\n )\n break\n }\n }\n } else {\n if (isDisabled.value) {\n classParts.push('text-foreground-disabled')\n } else if (!hasCustomTextColor) {\n if (props.color === 'invert') {\n classParts.push(\n 'text-foundation hover:text-foundation-2 dark:text-foreground dark:hover:text-foreground'\n )\n } else if (props.color === 'secondary') {\n classParts.push('text-foreground-2 hover:text-primary-focus')\n } else if (props.color === 'success') {\n classParts.push('text-success')\n } else if (props.color === 'warning') {\n classParts.push('text-warning')\n } else if (props.color === 'info') {\n classParts.push('text-info')\n } else if (props.color === 'danger') {\n classParts.push('text-danger')\n } else {\n classParts.push('text-primary hover:text-primary-focus')\n }\n }\n }\n return classParts.join(' ')\n})\n\nconst roundedClasses = computed(() => {\n const classParts: string[] = []\n classParts.push(props.rounded ? 'rounded-full' : 'rounded-md')\n return classParts.join(' ')\n})\n\nconst ringClasses = computed(() => {\n const classParts: string[] = []\n if (!isDisabled.value) {\n switch (props.color) {\n case 'invert':\n classParts.push('hover:ring-4 ring-white/50')\n break\n case 'danger':\n classParts.push('hover:ring-4 ring-danger-lighter dark:ring-danger-darker')\n break\n case 'warning':\n classParts.push('hover:ring-4 ring-warning-lighter dark:ring-warning-darker')\n break\n case 'info':\n classParts.push('hover:ring-4 ring-info-lighter dark:ring-info-darker')\n break\n case 'success':\n classParts.push('hover:ring-4 ring-success-lighter dark:ring-success-darker')\n break\n case 'default':\n default:\n classParts.push('hover:ring-2')\n break\n }\n }\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed(() => {\n switch (props.size) {\n case 'xs':\n return 'h-5 text-xs font-medium xxx-tracking-wide'\n case 'sm':\n return 'h-6 text-sm font-medium xxx-tracking-wide'\n case 'lg':\n return 'h-10 text-lg font-semibold xxx-tracking-wide'\n case 'xl':\n return 'h-14 text-xl font-bold xxx-tracking-wide'\n default:\n case 'base':\n return 'h-8 text-sm sm:text-base font-medium xxx-tracking-wide'\n }\n})\n\nconst paddingClasses = computed(() => {\n switch (props.size) {\n case 'xs':\n return 'px-1'\n case 'sm':\n return 'px-2'\n case 'lg':\n return 'px-4'\n case 'xl':\n return 'px-5'\n default:\n case 'base':\n return 'px-3'\n }\n})\n\nconst generalClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.fullWidth) {\n classParts.push('w-full')\n }\n\n if (isDisabled.value) {\n classParts.push('cursor-not-allowed')\n }\n\n return classParts.join(' ')\n})\n\nconst decoratorClasses = computed(() => {\n const classParts: string[] = []\n if (!isDisabled.value && !props.link && !props.text) {\n classParts.push('active:scale-[0.97]')\n }\n\n if (!isDisabled.value && props.link) {\n classParts.push(\n 'underline decoration-transparent decoration-2 underline-offset-4\thover:decoration-inherit'\n )\n }\n\n return classParts.join(' ')\n})\n\nconst buttonClasses = computed(() => {\n const isLinkOrText = props.link || props.text\n return [\n 'transition inline-flex justify-center text-center items-center outline-none select-none leading-[0.9rem]',\n generalClasses.value,\n sizeClasses.value,\n foregroundClasses.value,\n isLinkOrText ? '' : bgAndBorderClasses.value,\n isLinkOrText ? '' : roundedClasses.value,\n isLinkOrText ? '' : ringClasses.value,\n props.link ? '' : paddingClasses.value,\n decoratorClasses.value\n ].join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['']\n\n if (props.loading) {\n classParts.push('animate-spin')\n }\n\n switch (props.size) {\n case 'xs':\n classParts.push('h-3 w-3')\n break\n case 'sm':\n classParts.push('h-4 w-4')\n break\n case 'lg':\n classParts.push('h-6 w-6')\n break\n case 'xl':\n classParts.push('h-8 w-8')\n break\n case 'base':\n default:\n classParts.push('h-5 w-5')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst onClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n return\n }\n\n emit('click', e)\n}\n</script>\n<style scoped>\n.icon-slot:empty {\n display: none;\n}\n</style>\n","<template>\n <FormButton\n :link=\"!noUnderline\"\n :text=\"noUnderline\"\n :to=\"to\"\n :external=\"external\"\n :disabled=\"disabled\"\n :size=\"size\"\n :foreground-link=\"foregroundLink\"\n :icon-left=\"iconLeft\"\n :icon-right=\"iconRight\"\n :hide-text=\"hideText\"\n role=\"link\"\n @click.capture=\"onClick\"\n >\n <slot>Link</slot>\n </FormButton>\n</template>\n<script setup lang=\"ts\">\nimport FormButton from '~~/src/components/form/Button.vue'\nimport type { PropType } from 'vue'\nimport type { Nullable, Optional } from '@speckle/shared'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype LinkSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl'\nconst emit = defineEmits([\"click\"])\n\nconst props = defineProps({\n to: {\n type: String as PropType<Optional<string>>,\n required: false,\n default: undefined\n },\n external: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n disabled: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n size: {\n type: String as PropType<LinkSize>,\n default: 'base'\n },\n foregroundLink: {\n type: Boolean,\n default: false\n },\n /**\n * Add icon to the left from the text\n */\n iconLeft: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Add icon to the right from the text\n */\n iconRight: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Hide default slot (when you want to show icons only)\n */\n hideText: {\n type: Boolean,\n default: false\n },\n noUnderline: {\n type: Boolean,\n default: false\n }\n})\n\nconst onClick = (e: MouseEvent) => {\n if (props.disabled) {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n return\n }\n\n emit('click', e)\n}\n</script>\n","export enum ToastNotificationType {\n Success,\n Warning,\n Danger,\n Info\n}\n\nexport type ToastNotification = {\n title?: string\n /**\n * Optionally provide extra text\n */\n description?: string\n type: ToastNotificationType\n /**\n * Optionally specify a CTA link on the right\n */\n cta?: {\n title: string\n url?: string\n onClick?: (e: MouseEvent) => void\n }\n /**\n * Whether or not the toast should disappear automatically after a while.\n * Defaults to true\n */\n autoClose?: boolean\n}\n","<template>\n <div\n aria-live=\"assertive\"\n class=\"pointer-events-none fixed inset-0 flex items-end px-4 py-6 mt-10 sm:items-start sm:p-6 z-50\"\n >\n <div class=\"flex w-full flex-col items-center gap-4 sm:items-end\">\n <!-- Notification panel, dynamically insert this into the live region when it needs to be displayed -->\n <Transition\n enter-active-class=\"transform ease-out duration-300 transition\"\n enter-from-class=\"translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2\"\n enter-to-class=\"translate-y-0 opacity-100 sm:translate-x-0\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"notification\"\n class=\"pointer-events-auto w-full max-w-[20rem] overflow-hidden rounded-lg bg-foundation text-foreground shadow-lg ring-1 ring-primary-muted ring-opacity-5\"\n :class=\"isTitleOnly ? 'p-2' : 'p-3'\"\n >\n <div class=\"flex gap-2\" :class=\"isTitleOnly ? 'items-center' : 'items-start'\">\n <div class=\"flex-shrink-0\">\n <CheckCircleIcon\n v-if=\"notification.type === ToastNotificationType.Success\"\n class=\"text-success\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n <XCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Danger\"\n class=\"text-danger\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n <ExclamationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Warning\"\n class=\"text-warning\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n <InformationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Info\"\n class=\"text-info\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n </div>\n <div class=\"w-full min-w-[10rem]\">\n <p\n v-if=\"notification.title\"\n class=\"text-foreground font-bold\"\n :class=\"isTitleOnly ? 'text-sm' : 'text-base'\"\n >\n {{ notification.title }}\n </p>\n <p\n v-if=\"notification.description\"\n class=\"label label--light text-foreground-2 text-sm\"\n >\n {{ notification.description }}\n </p>\n <div v-if=\"notification.cta\">\n <CommonTextLink\n :to=\"notification.cta.url\"\n class=\"label\"\n size=\"xs\"\n primary\n @click=\"onCtaClick\"\n >\n {{ notification.cta.title }}\n </CommonTextLink>\n </div>\n </div>\n <div class=\"ml-2 flex-shrink-0\" :class=\"isTitleOnly ? 'mt-1.5' : ''\">\n <button\n type=\"button\"\n class=\"inline-flex rounded-md bg-foundation text-foreground-2 hover:text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2\"\n @click=\"dismiss\"\n >\n <span class=\"sr-only\">Close</span>\n <XMarkIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport CommonTextLink from '~~/src/components/common/text/Link.vue'\nimport {\n CheckCircleIcon,\n XCircleIcon,\n ExclamationCircleIcon,\n InformationCircleIcon\n} from '@heroicons/vue/24/outline'\nimport { XMarkIcon } from '@heroicons/vue/20/solid'\nimport { computed } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport { ToastNotificationType } from '~~/src/helpers/global/toast'\nimport type { ToastNotification } from '~~/src/helpers/global/toast'\n\nconst emit = defineEmits([\"update:notification\"])\n\nconst props = defineProps({\n notification: null\n})\n\nconst isTitleOnly = computed(\n () => !props.notification?.description && !props.notification?.cta\n)\n\nconst dismiss = () => {\n emit('update:notification', null)\n}\n\nconst onCtaClick = (e: MouseEvent) => {\n props.notification?.cta?.onClick?.(e)\n dismiss()\n}\n</script>\n","const KEYBOARD_CLICK_CHAR = 'Enter'\n\n/**\n * Visible, non-interactive elements with click handlers must have at least one keyboard listener for accessibility.\n * You can wrap your click handler with this in @keypress, to run it when enter is pressed on the selected component\n * See more: https://github.com/vue-a11y/eslint-plugin-vuejs-accessibility/blob/main/docs/click-events-have-key-events.md\n */\nexport function keyboardClick(cb: (e: KeyboardEvent) => void) {\n return (e: KeyboardEvent) => {\n if (e.code !== KEYBOARD_CLICK_CHAR) return\n cb(e)\n }\n}\n","<template>\n <span :class=\"badgeClasses\">\n <svg v-if=\"dot\" :class=\"dotClasses\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n <slot>Badge</slot>\n <button v-if=\"iconLeft\" :class=\"iconClasses\" @click=\"onIconClick($event)\">\n <Component :is=\"iconLeft\" :class=\"['h-4 w-4', badgeDotIconColorClasses]\" />\n </button>\n </span>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype BadgeSize = 'base' | 'lg'\n\nconst emit = defineEmits([\"click-icon\"])\n\nconst props = defineProps({\n size: null,\n colorClasses: null,\n dot: { type: Boolean },\n dotIconColorClasses: null,\n iconLeft: null,\n rounded: { type: Boolean },\n clickableIcon: { type: Boolean }\n})\n\nconst badgeColorClasses = computed(\n () => props.colorClasses || 'bg-blue-100 text-blue-800'\n)\n\nconst badgeDotIconColorClasses = computed(\n () => props.dotIconColorClasses || 'text-blue-400'\n)\n\nconst badgeClasses = computed(() => {\n const classParts: string[] = [\n 'inline-flex items-center',\n badgeColorClasses.value,\n props.size === 'lg' ? 'px-3 py-0.5 label' : 'px-2.5 py-0.5 caption font-medium'\n ]\n\n if (props.rounded) {\n classParts.push('rounded')\n classParts.push(\n props.size === 'lg' ? 'px-2 py-0.5 label' : 'px-2.5 py-0.5 caption font-medium'\n )\n } else {\n classParts.push('rounded-full')\n classParts.push(\n props.size === 'lg' ? 'px-2.5 py-0.5 label' : 'px-2.5 py-0.5 caption font-medium'\n )\n }\n\n return classParts.join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = [\n 'mt-0.5 ml-0.5 inline-flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-full focus:outline-none'\n ]\n\n if (props.clickableIcon) {\n classParts.push('cursor-pointer')\n } else {\n classParts.push('cursor-default')\n }\n\n return classParts.join(' ')\n})\n\nconst dotClasses = computed(() => {\n const classParts: string[] = [\n '-ml-0.5 mr-1.5 h-2 w-2',\n badgeDotIconColorClasses.value\n ]\n\n return classParts.join(' ')\n})\n\nconst onIconClick = (e: MouseEvent) => {\n if (!props.clickableIcon) {\n e.stopPropagation()\n e.stopImmediatePropagation()\n e.preventDefault()\n return\n }\n\n emit('click-icon', e)\n}\n</script>\n","let junkVariable: string[] = []\n\n/**\n * If you use concatenation or variables to build tailwind classes, PurgeCSS won't pick up on them\n * during build and will not add them to the build. So you can use this function to just add string\n * literals of tailwind classes so PurgeCSS picks up on them.\n *\n * While you could just define an unused array of these classes, eslint/TS will bother you about the unused\n * variable so it's better to use this instead.\n */\nexport function markClassesUsed(classes: string[]) {\n // this doesn't do anything, except trick the compiler into thinking this isn't a pure\n // function so that the invocations aren't tree-shaken out\n junkVariable = junkVariable ? classes : classes.slice()\n}\n\n/**\n * Default tailwind breakpoint set. Each value is the minimum width (in pixels) expected for each breakpoint.\n */\nexport enum TailwindBreakpoints {\n sm = 640,\n md = 746,\n lg = 1024,\n xl = 1280,\n '2xl' = 1536\n}\n","import { computed } from 'vue'\nimport type { ToRefs } from 'vue'\nimport type {\n HorizontalOrVertical,\n StepCoreType\n} from '~~/src/helpers/common/components'\nimport { clamp } from 'lodash'\nimport { TailwindBreakpoints, markClassesUsed } from '~~/src/helpers/tailwind'\n\nexport type StepsPadding = 'base' | 'xs' | 'sm'\n\nexport function useStepsInternals(params: {\n props: ToRefs<{\n orientation?: HorizontalOrVertical\n steps: StepCoreType[]\n modelValue?: number\n goVerticalBelow?: TailwindBreakpoints\n nonInteractive?: boolean\n stepsPadding?: StepsPadding\n }>\n emit: {\n (e: 'update:modelValue', val: number): void\n }\n}) {\n const {\n props: {\n modelValue,\n steps,\n orientation,\n goVerticalBelow,\n nonInteractive,\n stepsPadding\n },\n emit\n } = params\n\n const finalOrientation = computed(\n (): HorizontalOrVertical =>\n orientation?.value === 'vertical' ? 'vertical' : 'horizontal'\n )\n\n const value = computed({\n get: () => clamp(modelValue?.value || 0, -1, steps.value.length),\n set: (newVal) => emit('update:modelValue', clamp(newVal, 0, steps.value.length))\n })\n\n const getStepDisplayValue = (step: number) => `${step + 1}`\n const isCurrentStep = (step: number) => step === value.value\n const isFinishedStep = (step: number) => step < value.value\n\n const switchStep = (newStep: number, e?: MouseEvent) => {\n if (nonInteractive?.value) {\n e?.preventDefault()\n e?.stopPropagation()\n e?.stopImmediatePropagation()\n return\n }\n\n value.value = newStep\n\n const stepObj = steps.value[value.value]\n stepObj?.onClick?.()\n }\n\n const listClasses = computed(() => {\n const classParts: string[] = ['flex']\n\n let paddingHorizontal: string\n let paddingVertical: string\n if (stepsPadding?.value === 'xs') {\n paddingHorizontal = 'space-x-2'\n paddingVertical = 'space-y-1'\n } else if (stepsPadding?.value === 'sm') {\n paddingHorizontal = 'space-x-4'\n paddingVertical = 'space-y-1'\n } else {\n paddingHorizontal = 'space-x-8'\n paddingVertical = 'space-y-4'\n }\n\n classParts.push('flex')\n if (finalOrientation.value === 'vertical' || goVerticalBelow?.value) {\n classParts.push(`flex-col ${paddingVertical} justify-center`)\n\n if (goVerticalBelow?.value === TailwindBreakpoints.sm) {\n classParts.push(\n `sm:flex-row sm:space-y-0 sm:justify-start sm:${paddingHorizontal} sm:items-center`\n )\n } else if (goVerticalBelow?.value === TailwindBreakpoints.md) {\n classParts.push(\n `md:flex-row md:space-y-0 md:justify-start md:${paddingHorizontal} md:items-center`\n )\n } else if (goVerticalBelow?.value === TailwindBreakpoints.lg) {\n classParts.push(\n `lg:flex-row lg:space-y-0 lg:justify-start lg:${paddingHorizontal} lg:items-center`\n )\n } else if (goVerticalBelow?.value === TailwindBreakpoints.xl) {\n classParts.push(\n `xl:flex-row xl:space-y-0 xl:justify-start xl:${paddingHorizontal} xl:items-center`\n )\n }\n } else {\n classParts.push(`flex-row ${paddingHorizontal} items-center`)\n }\n\n return classParts.join(' ')\n })\n\n const linkClasses = computed(() => {\n const classParts: string[] = ['flex items-center']\n\n if (!nonInteractive?.value) {\n classParts.push('cursor-pointer')\n }\n\n return classParts.join(' ')\n })\n\n return {\n value,\n isCurrentStep,\n isFinishedStep,\n switchStep,\n getStepDisplayValue,\n listClasses,\n linkClasses,\n orientation: finalOrientation\n }\n}\n\n// to allow for dynamic class building above:\nmarkClassesUsed([\n 'sm:space-x-8',\n 'md:space-x-8',\n 'lg:space-x-8',\n 'xl:space-x-8',\n 'sm:space-x-2',\n 'md:space-x-2',\n 'lg:space-x-2',\n 'xl:space-x-2',\n 'sm:space-x-4',\n 'md:space-x-4',\n 'lg:space-x-4',\n 'xl:space-x-4'\n])\n","<template>\n <nav class=\"flex justify-center\" :aria-label=\"ariaLabel || 'Progress steps'\">\n <ol :class=\"listClasses\">\n <li v-for=\"(step, i) in steps\" :key=\"step.name\">\n <a\n v-if=\"isFinishedStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"flex space-x-3 items-center text-primary-focus normal font-medium leading-5\"\n >\n <div\n class=\"shrink-0 h-8 w-8 rounded-full bg-primary-focus text-foreground-on-primary inline-flex items-center justify-center\"\n >\n <CheckIcon class=\"w-5 h-5\" />\n </div>\n <div class=\"flex flex-col\">\n <div>{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"label label--light text-foreground\">\n {{ step.description }}\n </div>\n </div>\n </div>\n </a>\n <a\n v-else-if=\"isCurrentStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n aria-current=\"step\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"flex space-x-3 items-center text-primary-focus normal font-medium leading-5\"\n >\n <div\n class=\"shrink-0 h-8 w-8 rounded-full border-2 border-primary-focus inline-flex items-center justify-center\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div>{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"label label--light text-foreground\">\n {{ step.description }}\n </div>\n </div>\n </div>\n </a>\n <a\n v-else\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"flex space-x-3 items-center text-foreground-disabled normal font-medium leading-5\"\n >\n <div\n class=\"shrink-0 h-8 w-8 rounded-full border-2 border-foreground-disabled inline-flex items-center justify-center\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div>{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"label label--light\">\n {{ step.description }}\n </div>\n </div>\n </div>\n </a>\n </li>\n </ol>\n </nav>\n</template>\n<script setup lang=\"ts\">\nimport { CheckIcon } from '@heroicons/vue/20/solid'\nimport { toRefs } from 'vue'\nimport { useStepsInternals } from '~~/src/composables/common/steps'\nimport type { StepsPadding } from '~~/src/composables/common/steps'\nimport type {\n HorizontalOrVertical,\n NumberStepType\n} from '~~/src/helpers/common/components'\nimport { TailwindBreakpoints } from '~~/src/helpers/tailwind'\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n ariaLabel: null,\n orientation: null,\n steps: null,\n modelValue: null,\n goVerticalBelow: null,\n nonInteractive: { type: Boolean },\n stepsPadding: null\n})\n\nconst {\n isCurrentStep,\n isFinishedStep,\n switchStep,\n getStepDisplayValue,\n listClasses,\n linkClasses\n} = useStepsInternals({\n props: toRefs(props),\n emit\n})\n</script>\n","<template>\n <nav class=\"flex justify-center\" :aria-label=\"ariaLabel || 'Progress steps'\">\n <ol :class=\"[listClasses, extraListClasses]\">\n <li v-for=\"(step, i) in steps\" :key=\"step.name\">\n <a\n v-if=\"isFinishedStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <span class=\"relative flex h-5 w-5 flex-shrink-0 items-center justify-center\">\n <span v-if=\"basic\" class=\"h-3 w-3 rounded-full bg-foreground-2\" />\n <CheckCircleIcon\n v-else\n class=\"h-full w-full text-primary\"\n aria-hidden=\"true\"\n />\n </span>\n <span :class=\"['text-foreground', labelClasses]\">\n {{ step.name }}\n </span>\n </a>\n <a\n v-else-if=\"isCurrentStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n aria-current=\"step\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <span\n class=\"relative flex h-5 w-5 flex-shrink-0 items-center justify-center\"\n aria-hidden=\"true\"\n >\n <template v-if=\"basic\">\n <span class=\"h-3 w-3 rounded-full bg-foreground\" />\n </template>\n <template v-else>\n <span class=\"absolute h-4 w-4 rounded-full bg-outline-2\" />\n <span class=\"relative block h-2 w-2 rounded-full bg-primary-focus\" />\n </template>\n </span>\n <span :class=\"['text-primary-focus', labelClasses]\">\n {{ step.name }}\n </span>\n </a>\n <a\n v-else\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"relative flex h-5 w-5 flex-shrink-0 items-center justify-center\"\n aria-hidden=\"true\"\n >\n <span v-if=\"basic\" class=\"h-3 w-3 rounded-full bg-foreground-2\" />\n <div v-else class=\"h-4 w-4 rounded-full bg-foreground-disabled\" />\n </div>\n <p :class=\"['text-foreground-disabled', labelClasses]\">\n {{ step.name }}\n </p>\n </a>\n </li>\n </ol>\n </nav>\n</template>\n<script setup lang=\"ts\">\nimport { CheckCircleIcon } from '@heroicons/vue/20/solid'\nimport { computed, toRefs } from 'vue'\nimport { useStepsInternals } from '~~/src/composables/common/steps'\nimport type { StepsPadding } from '~~/src/composables/common/steps'\nimport type {\n BulletStepType,\n HorizontalOrVertical\n} from '~~/src/helpers/common/components'\nimport { TailwindBreakpoints } from '~~/src/helpers/tailwind'\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n ariaLabel: null,\n basic: { type: Boolean },\n orientation: null,\n steps: null,\n modelValue: null,\n goVerticalBelow: null,\n nonInteractive: { type: Boolean },\n stepsPadding: null\n})\n\nconst { isCurrentStep, isFinishedStep, switchStep, listClasses, linkClasses } =\n useStepsInternals({\n props: toRefs(props),\n emit\n })\n\nconst labelClasses = computed(() => {\n const classParts: string[] = ['h6 font-medium leading-7']\n\n let leftMargin: string\n if (props.stepsPadding === 'xs') {\n leftMargin = 'ml-1'\n } else if (props.stepsPadding === 'sm') {\n leftMargin = 'ml-2'\n } else {\n leftMargin = 'ml-3'\n }\n\n classParts.push(leftMargin)\n\n if (props.basic) {\n classParts.push('sr-only')\n }\n\n return classParts.join(' ')\n})\n\nconst extraListClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.basic) {\n classParts.push('basic')\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"icon icon-tabler icon-tabler-pointer\"\n width=\"44\"\n height=\"44\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n fill=\"rgba(255,255,255,0.8)\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n <path\n d=\"M7.904 17.563a1.2 1.2 0 0 0 2.228 .308l2.09 -3.093l4.907 4.907a1.067 1.067 0 0 0 1.509 0l1.047 -1.047a1.067 1.067 0 0 0 0 -1.509l-4.907 -4.907l3.113 -2.09a1.2 1.2 0 0 0 -.309 -2.228l-13.582 -3.904l3.904 13.563z\"\n />\n </svg>\n</template>\n","<template>\n <svg viewBox=\"0 0 18 17\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M9 1.25V3.5M14.834 3.666L13.243 5.257M17.25 9.5H15M4.757 13.743L3.167 15.333M3 9.5H0.75M4.757 5.257L3.167 3.667\"\n stroke=\"currentColor\"\n stroke-width=\"1\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n","<template>\n <div\n class=\"relative aspect-square w-full h-full max-w-[250px] mx-auto mb-8 border-t border-r border-outline-3 select-none\"\n >\n <div\n class=\"absolute z-50 text-foreground dark:text-foundation\"\n :style=\"{\n transitionProperty: 'all',\n top: mousePosition.top + '%',\n left: mousePosition.left + '%',\n transitionDuration: animationDuration + 'ms'\n }\"\n >\n <ClickIcon\n class=\"absolute -top-5 -left-4 h-12 w-12 -rotate-12 text-foreground\"\n :class=\"[{ hidden: !isClicked }]\"\n />\n <MouseIcon class=\"absolute inset-0 h-11 w-11\" />\n </div>\n <div class=\"w-full h-full overflow-hidden\">\n <slot name=\"background\"></slot>\n <template v-for=\"slotObject in dynamicSlots\" :key=\"slotObject.name\">\n <template v-if=\"slotObject.visible\">\n <slot :name=\"slotObject.name\"></slot>\n </template>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, defineProps, type PropType, onBeforeUnmount } from 'vue'\nimport MouseIcon from '~~/src/components/common/animation/MouseIcon.vue'\nimport ClickIcon from '~~/src/components/common/animation/ClickIcon.vue'\nimport { wait } from '@speckle/shared'\n\ntype AnimationAction = {\n type: 'animation'\n top: number\n left: number\n duration: number\n}\n\ntype ClickAction = {\n type: 'click'\n}\n\ntype DelayAction = {\n type: 'delay'\n duration: number\n}\n\ntype SlotAction = {\n type: 'slot'\n slot: string\n}\n\ntype Action = AnimationAction | ClickAction | SlotAction | DelayAction\n\nconst props = defineProps({\n actions: Array as PropType<Action[]>,\n initialPosition: {\n type: Object as PropType<{ top: number; left: number }>\n },\n slotsConfig: Array as PropType<{ name: string; visible: boolean }[]>\n})\n\nconst isAnimating = ref(true)\nconst mousePosition = ref({ ...props.initialPosition })\nconst isClicked = ref(false)\nconst animationDuration = ref(500)\nconst isMouseVisible = ref(true)\nconst dynamicSlots = ref(props.slotsConfig || [])\n\nasync function delay(action: DelayAction) {\n await wait(action.duration)\n}\n\nfunction toggleSlotVisibility(action: SlotAction) {\n const slotToToggle = dynamicSlots.value.find((slot) => slot.name === action.slot)\n if (slotToToggle) {\n slotToToggle.visible = !slotToToggle.visible\n }\n}\n\nfunction handleAction(action: Action) {\n switch (action.type) {\n case 'animation':\n mousePosition.value = { top: action.top, left: action.left }\n animationDuration.value = action.duration\n break\n case 'click':\n isClicked.value = true\n setTimeout(() => (isClicked.value = false), 500)\n break\n case 'delay':\n return delay(action)\n case 'slot':\n toggleSlotVisibility(action as SlotAction)\n break\n }\n}\n\nonMounted(() => {\n const loopActions = async () => {\n while (isAnimating.value) {\n await delay({ type: 'delay', duration: 800 })\n isMouseVisible.value = true\n for (const action of props.actions || []) {\n await handleAction(action)\n }\n isMouseVisible.value = false\n mousePosition.value = { ...props.initialPosition }\n await delay({ type: 'delay', duration: 200 })\n }\n }\n\n loopActions()\n})\n\nonBeforeUnmount(() => {\n isAnimating.value = false\n})\n</script>\n","<template>\n <button :class=\"computedClasses\" :disabled=\"disabled\" @click=\"onClick\">\n <slot>Text</slot>\n </button>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst emit = defineEmits([\"update:modelValue\", \"click\"])\n\nconst props = defineProps({\n disabled: { type: Boolean },\n modelValue: { type: Boolean }\n})\n\nconst computedClasses = computed(() => {\n const classParts: string[] = [\n 'h-20 bg-foundation-2 inline-flex justify-center items-center outline-none',\n 'normal px-16 py-5 shadow rounded transition active:scale-95'\n ]\n\n if (props.disabled) {\n classParts.push('bg-foundation-disabled text-foreground-2 cursor-not-allowed')\n } else {\n classParts.push(\n props.modelValue\n ? 'bg-primary-focus text-foreground-on-primary'\n : 'bg-foundation text-foreground'\n )\n classParts.push('ring-outline-2 hover:ring-4')\n }\n\n return classParts.join(' ')\n})\n\nconst onClick = (e: MouseEvent) => {\n if (props.disabled) {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n return\n }\n\n emit('update:modelValue', !props.modelValue)\n emit('click', e)\n}\n</script>\n","<template>\n <div class=\"relative flex items-start\">\n <div class=\"flex h-6 items-center\">\n <!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->\n <input\n :id=\"finalId\"\n :checked=\"coreChecked\"\n :aria-describedby=\"descriptionId\"\n :name=\"name\"\n :disabled=\"disabled\"\n :value=\"checkboxValue\"\n type=\"checkbox\"\n class=\"h-4 w-4 rounded text-primary focus:ring-primary bg-foundation disabled:cursor-not-allowed disabled:bg-disabled disabled:text-disabled-2\"\n :class=\"computedClasses\"\n v-bind=\"$attrs\"\n @change=\"onChange\"\n />\n </div>\n <div class=\"ml-2 text-sm\" style=\"padding-top: 2px\">\n <label\n :for=\"finalId\"\n class=\"font-medium text-foreground\"\n :class=\"{ 'sr-only': hideLabel }\"\n >\n <span>{{ title }}</span>\n <span v-if=\"showRequired\" class=\"text-danger ml-1\">*</span>\n </label>\n <p v-if=\"descriptionText\" :id=\"descriptionId\" :class=\"descriptionClasses\">\n {{ descriptionText }}\n </p>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, onMounted, ref } from 'vue'\nimport type { PropType } from 'vue'\nimport type { Optional } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\n\n/**\n * Troubleshooting:\n * - If clicking on the checkbox doesn't do anything, check if any of its ancestor elements\n * have a @click.prevent on them anywhere.\n * - If you're not using the checkbox in a group, it's suggested that you set :value=\"true\",\n * so that a v-model attached to the checkbox will be either 'true' or 'undefined' depending on the\n * checked state\n */\n\ntype ValueType = Optional<string | true> | string[]\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst props = defineProps({\n /**\n * Input name/id. In a checkbox group, all checkboxes must have the same name and different values.\n */\n name: {\n type: String,\n required: true\n },\n /**\n * Whether the input is disabled\n */\n disabled: {\n type: Boolean,\n default: false\n },\n /**\n * Set label text\n */\n label: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Help text\n */\n description: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Whether to inline the help description\n */\n inlineDescription: {\n type: Boolean,\n default: false\n },\n /**\n * vee-validate validation rules\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<ValueType>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Checkbox group's value\n */\n modelValue: {\n type: [String, Boolean] as PropType<ValueType | false>,\n default: undefined\n },\n /**\n * Checkbox's own value. If it is checked, modelValue will include this value (amongst any other checked values from the same group).\n * If not set will default to 'name' value.\n */\n value: {\n type: [String, Boolean] as PropType<Optional<string | true>>,\n default: true\n },\n /**\n * HTML ID to use, must be globally unique. If not specified, a random ID will be generated. One is necessary to properly associate the label and checkbox.\n */\n id: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n hideLabel: {\n type: Boolean,\n default: false\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits([\"update:modelValue\"])\n\nconst checkboxValue = computed(() => props.value || props.name)\n\nconst {\n checked: coreChecked,\n errorMessage,\n handleChange,\n value: coreValue\n} = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n type: 'checkbox',\n checkedValue: checkboxValue,\n initialValue: props.modelValue || undefined\n})\n\nconst title = computed(() => props.label || props.name)\n\nconst computedClasses = computed((): string => {\n return errorMessage.value ? 'border-danger-lighter' : 'border-foreground-4 '\n})\n\nconst descriptionText = computed(() => props.description || errorMessage.value)\nconst descriptionId = computed(() => `${props.name}-description`)\nconst descriptionClasses = computed((): string => {\n const classParts: string[] = []\n\n if (props.inlineDescription) {\n classParts.push('inline ml-2')\n } else {\n classParts.push('block')\n }\n\n if (errorMessage.value) {\n classParts.push('text-danger')\n } else {\n classParts.push('text-foreground-2')\n }\n\n return classParts.join(' ')\n})\n\nconst implicitId = ref<Optional<string>>(generateRandomId('checkbox'))\nconst finalId = computed(() => props.id || implicitId.value)\n\nconst onChange = (e: unknown) => {\n if (props.disabled) return\n handleChange(e)\n}\n\n/**\n * Bugfix for strange issue where checkbox appears checked even tho it shouldnt be.\n * It's not clear why this happens, but for some reason coreValue.value shows that the checkbox\n * is checked, even tho props.modelValue is undefined.\n */\nonMounted(() => {\n const newModelValue = props.modelValue\n const newCoreValue = coreValue.value\n\n const shouldBeChecked = Array.isArray(newModelValue)\n ? newModelValue.includes(props.value as any)\n : newModelValue === props.value\n\n const isCoreChecked = Array.isArray(newCoreValue)\n ? newCoreValue.includes(props.value as any)\n : newCoreValue === props.value\n\n if (shouldBeChecked !== isCoreChecked) {\n handleChange(newModelValue)\n }\n})\n</script>\n","<template>\n <div\n class=\"relative flex gap-2 mb-2 last:mb-0\"\n :class=\"description && inlineDescription ? 'items-start' : 'items-center'\"\n >\n <div class=\"flex h-6 items-center\">\n <!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->\n <input\n :id=\"finalId\"\n :checked=\"coreChecked\"\n :aria-describedby=\"descriptionId\"\n :name=\"name\"\n :disabled=\"disabled\"\n :value=\"radioValue\"\n type=\"radio\"\n class=\"h-4 w-4 rounded-full text-primary focus:ring-primary bg-foundation disabled:cursor-not-allowed disabled:bg-disabled disabled:text-disabled-2\"\n :class=\"computedClasses\"\n v-bind=\"$attrs\"\n @change=\"onChange\"\n />\n </div>\n <div\n class=\"text-xs sm:text-sm\"\n :class=\"inlineDescription ? 'flex gap-2 items-center' : ''\"\n >\n <label\n :for=\"finalId\"\n class=\"text-foreground flex gap-2 items-center\"\n :class=\"{ 'sr-only': hideLabel }\"\n >\n <div v-if=\"icon\" class=\"text-sm\">\n <component :is=\"icon\" class=\"h-8 sm:h-10 w-8 sm:w-10\"></component>\n </div>\n <div class=\"flex flex-col\">\n <span>{{ title }}</span>\n <p\n v-if=\"descriptionText && !inlineDescription\"\n :id=\"descriptionId\"\n :class=\"descriptionClasses\"\n >\n {{ descriptionText }}\n </p>\n </div>\n <span v-if=\"showRequired\" class=\"text-danger ml-1\">*</span>\n </label>\n <p\n v-if=\"descriptionText && inlineDescription\"\n :id=\"descriptionId\"\n :class=\"descriptionClasses\"\n >\n {{ descriptionText }}\n </p>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, onMounted, ref } from 'vue'\nimport type { PropType, ConcreteComponent } from 'vue'\nimport type { Optional } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\n\n/**\n * Troubleshooting:\n * - If clicking on the radio doesn't do anything, check if any of its ancestor elements\n * have a @click.prevent on them anywhere.\n * - If you're not using the radio in a group, it's suggested that you set :value=\"true\",\n * so that a v-model attached to the radio will be either 'true' or 'undefined' depending on the\n * checked state\n */\n\ntype ValueType = Optional<string | true> | string[]\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst props = defineProps({\n /**\n * Input name/id. In a radio group, all radios must have the same name and different values.\n */\n name: {\n type: String,\n required: true\n },\n /**\n * Whether the input is disabled\n */\n disabled: {\n type: Boolean,\n default: false\n },\n /**\n * Set label text\n */\n label: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Help text\n */\n description: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Whether to inline the help description\n */\n inlineDescription: {\n type: Boolean,\n default: false\n },\n /**\n * Optional Icon\n */\n icon: {\n type: Object as PropType<ConcreteComponent>,\n default: undefined\n },\n /**\n * vee-validate validation rules\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<ValueType>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Radio group's value\n */\n modelValue: {\n type: [String, Boolean] as PropType<ValueType | false>,\n default: undefined\n },\n /**\n * Radio's own value. If it is checked, modelValue will include this value (amongst any other checked values from the same group).\n * If not set will default to 'name' value.\n */\n value: {\n type: [String, Boolean] as PropType<Optional<string | true>>,\n default: true\n },\n /**\n * HTML ID to use, must be globally unique. If not specified, a random ID will be generated. One is necessary to properly associate the label and radio.\n */\n id: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n hideLabel: {\n type: Boolean,\n default: false\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits([\"update:modelValue\"])\n\nconst radioValue = computed(() => props.value || props.name)\n\nconst {\n checked: coreChecked,\n errorMessage,\n handleChange,\n value: coreValue\n} = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n type: 'radio',\n checkedValue: radioValue,\n initialValue: props.modelValue || undefined\n})\n\nconst title = computed(() => props.label || props.name)\n\nconst computedClasses = computed((): string => {\n return errorMessage.value ? 'border-danger-lighter' : 'border-foreground-4 '\n})\n\nconst descriptionText = computed(() => props.description || errorMessage.value)\nconst descriptionId = computed(() => `${props.name}-description`)\nconst descriptionClasses = computed((): string => {\n const classParts: string[] = ['text-xs']\n\n if (errorMessage.value) {\n classParts.push('text-danger')\n } else {\n classParts.push('text-foreground-2')\n }\n\n return classParts.join(' ')\n})\n\nconst implicitId = ref<Optional<string>>(generateRandomId('radio'))\nconst finalId = computed(() => props.id || implicitId.value)\n\nconst onChange = (e: unknown) => {\n if (props.disabled) return\n handleChange(e)\n}\n\n/**\n * Bugfix for strange issue where radio appears checked even tho it shouldnt be.\n * It's not clear why this happens, but for some reason coreValue.value shows that the radio\n * is checked, even tho props.modelValue is undefined.\n */\nonMounted(() => {\n const newModelValue = props.modelValue\n const newCoreValue = coreValue.value\n\n const shouldBeChecked = Array.isArray(newModelValue)\n ? newModelValue.includes(props.value as any)\n : newModelValue === props.value\n\n const isCoreChecked = Array.isArray(newCoreValue)\n ? newCoreValue.includes(props.value as any)\n : newCoreValue === props.value\n\n if (shouldBeChecked !== isCoreChecked) {\n handleChange(newModelValue)\n }\n})\n</script>\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, onMounted, ref, unref } from 'vue'\nimport type { Ref, ToRefs } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\nimport { isArray } from 'lodash'\n\nexport type InputColor = 'page' | 'foundation' | 'transparent'\n\n/**\n * Common setup for text input & textarea fields\n */\nexport function useTextInputCore<V extends string | string[] = string>(params: {\n props: ToRefs<{\n name: string\n help?: string\n label?: string\n showLabel?: boolean\n rules?: RuleExpression<V>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n modelValue?: V\n autoFocus?: boolean\n showClear?: boolean\n useLabelInErrors?: boolean\n hideErrorMessage?: boolean\n color?: InputColor\n }>\n emit: {\n (e: 'change', val: { event?: Event; value: V }): void\n (e: 'clear'): void\n }\n inputEl: Ref<Nullable<HTMLInputElement | HTMLTextAreaElement>>\n options?: Partial<{\n customClear: () => void\n }>\n}) {\n const { props, inputEl, emit, options } = params\n\n const { value, errorMessage: error } = useField<V>(props.name, props.rules, {\n validateOnMount: unref(props.validateOnMount),\n validateOnValueUpdate: unref(props.validateOnValueUpdate),\n initialValue: unref(props.modelValue) || undefined\n })\n\n const labelClasses = computed(() => {\n const classParts = ['block label text-foreground-2 mb-2']\n if (!unref(props.showLabel)) {\n classParts.push('sr-only')\n }\n\n return classParts.join(' ')\n })\n\n const coreInputClasses = computed(() => {\n const classParts: string[] = [\n 'focus:outline-none disabled:cursor-not-allowed disabled:bg-foundation-disabled',\n 'disabled:text-disabled-muted placeholder:text-foreground-2',\n 'rounded'\n ]\n\n return classParts.join(' ')\n })\n\n const coreClasses = computed(() => {\n const classParts = [\n 'block w-full text-foreground transition-all',\n coreInputClasses.value\n ]\n\n if (error.value) {\n classParts.push(\n 'focus:border-danger focus:ring-danger border-2 border-danger text-danger-darker'\n )\n } else {\n classParts.push('border-0 focus:ring-2 focus:ring-outline-2')\n }\n\n const color = unref(props.color)\n if (color === 'foundation') {\n classParts.push('bg-foundation shadow-sm hover:shadow')\n } else if (color === 'transparent') {\n classParts.push('bg-transparent')\n } else {\n classParts.push('bg-foundation-page')\n }\n\n return classParts.join(' ')\n })\n\n const internalHelpTipId = ref(nanoid())\n\n const title = computed(() => unref(props.label) || unref(props.name))\n const errorMessage = computed(() => {\n const base = error.value\n if (!base || !unref(props.useLabelInErrors)) return base\n return base.replace('Value', title.value)\n })\n\n const hideHelpTip = computed(\n () => errorMessage.value && unref(props.hideErrorMessage)\n )\n const helpTip = computed(() => errorMessage.value || unref(props.help))\n const hasHelpTip = computed(() => !!helpTip.value)\n const helpTipId = computed(() =>\n hasHelpTip.value ? `${unref(props.name)}-${internalHelpTipId.value}` : undefined\n )\n const helpTipClasses = computed((): string => {\n const classParts = ['mt-2 text-xs sm:text-sm']\n classParts.push(error.value ? 'text-danger' : 'text-foreground-2')\n return classParts.join(' ')\n })\n\n const focus = () => {\n inputEl.value?.focus()\n }\n\n const clear = () => {\n value.value = (isArray(value.value) ? [] : '') as V\n options?.customClear?.()\n\n emit('change', { value: value.value })\n emit('clear')\n }\n\n onMounted(() => {\n if (unref(props.autoFocus)) {\n focus()\n }\n })\n\n return {\n coreInputClasses,\n coreClasses,\n title,\n value,\n helpTipId,\n helpTipClasses,\n helpTip,\n hideHelpTip,\n errorMessage,\n clear,\n focus,\n labelClasses\n }\n}\n","<template>\n <div :class=\"[fullWidth ? 'w-full' : '']\">\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n <div class=\"relative\">\n <textarea\n :id=\"name\"\n ref=\"inputElement\"\n v-model=\"value\"\n :name=\"name\"\n :class=\"[\n coreClasses,\n iconClasses,\n textareaClasses || '',\n 'min-h-[3rem] simple-scrollbar text-sm'\n ]\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :aria-invalid=\"errorMessage ? 'true' : 'false'\"\n :aria-describedby=\"helpTipId\"\n v-bind=\"$attrs\"\n @change=\"$emit('change', { event: $event, value })\"\n @input=\"$emit('input', { event: $event, value })\"\n />\n <a\n v-if=\"showClear\"\n title=\"Clear input\"\n class=\"absolute top-2 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-if=\"errorMessage\"\n :class=\"[\n 'pointer-events-none absolute inset-y-0 right-0 flex items-start mt-2',\n showClear ? 'pr-8' : 'pr-2'\n ]\"\n >\n <ExclamationCircleIcon class=\"h-4 w-4 text-danger\" aria-hidden=\"true\" />\n </div>\n <div\n v-if=\"showRequired && !errorMessage\"\n class=\"pointer-events-none absolute inset-y-0 mt-0.5 text-4xl right-0 flex items-start text-danger opacity-50\"\n :class=\"[showClear ? 'pr-8' : 'pr-2']\"\n >\n *\n </div>\n </div>\n <p v-if=\"helpTipId\" :id=\"helpTipId\" :class=\"helpTipClasses\">\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { ExclamationCircleIcon, XMarkIcon } from '@heroicons/vue/20/solid'\nimport type { Nullable } from '@speckle/shared'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, ref, toRefs } from 'vue'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\n\nconst emit = defineEmits([\"update:modelValue\", \"change\", \"input\", \"clear\"])\n\nconst props = defineProps({\n name: null,\n showLabel: { type: Boolean },\n help: null,\n placeholder: null,\n label: null,\n disabled: { type: Boolean },\n rules: null,\n validateOnMount: { type: Boolean },\n validateOnValueUpdate: { type: Boolean },\n useLabelInErrors: { type: Boolean, default: true },\n autoFocus: { type: Boolean },\n modelValue: { default: '' },\n showClear: { type: Boolean },\n fullWidth: { type: Boolean },\n showRequired: { type: Boolean },\n color: { default: 'page' },\n textareaClasses: null\n})\n\nconst inputElement = ref(null as Nullable<HTMLTextAreaElement>)\n\nconst {\n coreClasses,\n title,\n value,\n helpTipId,\n helpTipClasses,\n helpTip,\n errorMessage,\n labelClasses,\n clear,\n focus\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl: inputElement\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['pl-2']\n\n if (props.showClear && errorMessage.value) {\n classParts.push('pr-12')\n } else if (props.showClear || errorMessage.value) {\n classParts.push('pr-8')\n }\n\n return classParts.join(' ')\n})\n\ndefineExpose({ focus })\n</script>\n","<template>\n <div :class=\"[fullWidth ? 'w-full' : '', wrapperClasses]\">\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n <div class=\"relative\">\n <div\n v-if=\"hasLeadingIcon\"\n class=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2\"\n >\n <Component\n :is=\"customIcon\"\n v-if=\"customIcon\"\n :class=\"leadingIconClasses\"\n aria-hidden=\"true\"\n />\n <EnvelopeIcon\n v-else-if=\"type === 'email'\"\n :class=\"leadingIconClasses\"\n aria-hidden=\"true\"\n />\n <KeyIcon\n v-else-if=\"type === 'password'\"\n :class=\"leadingIconClasses\"\n aria-hidden=\"true\"\n />\n </div>\n <input\n :id=\"name\"\n ref=\"inputElement\"\n v-model=\"value\"\n :type=\"type\"\n :name=\"name\"\n :class=\"[coreClasses, iconClasses, sizeClasses, inputClasses || '']\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :aria-invalid=\"errorMessage ? 'true' : 'false'\"\n :aria-describedby=\"helpTipId\"\n role=\"textbox\"\n v-bind=\"$attrs\"\n @change=\"$emit('change', { event: $event, value })\"\n @input=\"$emit('input', { event: $event, value })\"\n @focus=\"$emit('focus')\"\n @blur=\"$emit('blur')\"\n />\n <slot name=\"input-right\">\n <a\n v-if=\"showClear\"\n title=\"Clear input\"\n class=\"absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-if=\"errorMessage\"\n :class=\"[\n 'pointer-events-none absolute inset-y-0 right-0 flex items-center',\n showClear ? 'pr-8' : 'pr-2'\n ]\"\n >\n <ExclamationCircleIcon class=\"h-4 w-4 text-danger\" aria-hidden=\"true\" />\n </div>\n <div\n v-if=\"showRequired && !errorMessage\"\n class=\"pointer-events-none absolute inset-y-0 mt-3 text-4xl right-0 flex items-center text-danger opacity-50\"\n :class=\"[showClear ? 'pr-8' : 'pr-2']\"\n >\n *\n </div>\n </slot>\n </div>\n <p v-if=\"helpTipId && !hideHelpTip\" :id=\"helpTipId\" :class=\"helpTipClasses\">\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { RuleExpression } from 'vee-validate'\nimport {\n ExclamationCircleIcon,\n EnvelopeIcon,\n KeyIcon,\n XMarkIcon\n} from '@heroicons/vue/20/solid'\nimport { computed, ref, toRefs, useSlots } from 'vue'\nimport type { PropType } from 'vue'\nimport type { Nullable, Optional } from '@speckle/shared'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype InputType = 'text' | 'email' | 'password' | 'url' | 'search' | 'number' | string\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\ntype InputColor = 'page' | 'foundation' | 'transparent'\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst props = defineProps({\n /**\n * Input \"type\" value (changes behaviour & look)\n */\n type: {\n type: String as PropType<InputType>,\n default: 'text'\n },\n /**\n * Unique ID for the input (must be unique page-wide)\n */\n name: {\n type: String,\n required: true\n },\n /**\n * Whether to show label (label will always be shown to screen readers)\n */\n showLabel: {\n type: Boolean,\n required: false\n },\n /**\n * Optional help text\n */\n help: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Placeholder text\n */\n placeholder: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Set label text explicitly\n */\n label: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to disable the component, blocking it from user input\n */\n disabled: {\n type: Boolean,\n default: false\n },\n /**\n * vee-validate validation rules\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<string>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to trigger validation whenever the value changes\n */\n validateOnValueUpdate: {\n type: Boolean,\n default: false\n },\n /**\n * Will replace the generic \"Value\" text with the name of the input in error messages\n */\n useLabelInErrors: {\n type: Boolean,\n default: true\n },\n /**\n * Set a custom icon to use inside the input\n */\n customIcon: {\n type: [Object, Function] as PropType<Optional<PropAnyComponent>>,\n default: undefined\n },\n /**\n * Whether to focus on the input when component is mounted\n */\n autoFocus: {\n type: Boolean,\n default: false\n },\n modelValue: {\n type: String,\n default: ''\n },\n size: {\n type: String as PropType<InputSize>,\n default: 'base'\n },\n showClear: {\n type: Boolean,\n default: false\n },\n fullWidth: {\n type: Boolean,\n default: false\n },\n inputClasses: {\n type: String,\n default: null\n },\n hideErrorMessage: {\n type: Boolean,\n default: false\n },\n wrapperClasses: {\n type: String,\n default: () => ''\n },\n color: {\n type: String as PropType<InputColor>,\n default: 'page'\n }\n})\n\nconst emit = defineEmits([\"update:modelValue\", \"change\", \"input\", \"clear\", \"focus\", \"blur\"])\n\nconst slots = useSlots()\n\nconst inputElement = ref(null as Nullable<HTMLInputElement>)\n\nconst {\n coreClasses,\n title,\n value,\n helpTipId,\n helpTipClasses,\n helpTip,\n hideHelpTip,\n errorMessage,\n clear,\n focus,\n labelClasses\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl: inputElement\n})\n\nconst leadingIconClasses = computed(() => {\n const classParts: string[] = ['h-5 w-5']\n\n if (errorMessage.value) {\n classParts.push('text-danger')\n } else {\n classParts.push('text-foreground-2')\n }\n\n return classParts.join(' ')\n})\n\nconst hasLeadingIcon = computed(\n () => ['email', 'password'].includes(props.type) || props.customIcon\n)\n\nconst iconClasses = computed((): string => {\n const classParts: string[] = []\n\n if (hasLeadingIcon.value) {\n classParts.push('pl-8')\n } else {\n classParts.push('pl-2')\n }\n\n if (!slots['input-right']) {\n if (errorMessage.value || props.showClear) {\n if (errorMessage.value && props.showClear) {\n classParts.push('pr-12')\n } else {\n classParts.push('pr-8')\n }\n }\n }\n\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed((): string => {\n switch (props.size) {\n case 'sm':\n return 'h-6 text-sm'\n case 'lg':\n return 'h-10'\n case 'xl':\n return 'h-14'\n case 'base':\n default:\n return 'h-8 text-sm'\n }\n})\n\ndefineExpose({ focus })\n</script>\n","import { isString, isUndefined } from 'lodash'\nimport type { GenericValidateFunction } from 'vee-validate'\nimport { isNullOrUndefined } from '@speckle/shared'\n\nexport const VALID_HTTP_URL = /^https?:\\/\\//\nexport const VALID_EMAIL = /^[\\w-_.+]+@[\\w-_.+]+$/\n\n/**\n * Note about new validators:\n * Make sure you use the word \"Value\" to refer to the value being validated in all error messages, cause the dynamic string replace\n * that replaces that part with the actual field name works based on that\n */\n\n/**\n * E-mail validation rule (not perfect, but e-mails should be validated by sending out confirmation e-mails anyway)\n */\nexport const isEmail: GenericValidateFunction<string> = (val) =>\n (val || '').match(VALID_EMAIL) ? true : 'Value should be a valid e-mail address'\n\nexport const isOneOrMultipleEmails: GenericValidateFunction<string> = (val) => {\n const emails = (val || '').split(',').map((i) => i.trim())\n const valid = emails.every((e) => e.match(VALID_EMAIL))\n return valid || 'Value should be one or multiple comma-delimited e-mail addresses'\n}\n\nexport const isRequired: GenericValidateFunction<unknown> = (val) => {\n if (isString(val)) {\n val = val.trim()\n }\n\n return val ? true : 'Value is required'\n}\n\nexport const isSameAs: (\n otherFieldName: string,\n otherFieldDisplayName?: string\n) => GenericValidateFunction<unknown> =\n (otherFieldName, otherFieldDisplayName) => (val, meta) => {\n return val === meta.form[otherFieldName]\n ? true\n : `Value must be the same as in field '${\n otherFieldDisplayName || otherFieldName\n }'`\n }\n\nexport const isStringOfLength =\n (params: {\n minLength?: number\n maxLength?: number\n }): GenericValidateFunction<string> =>\n (val) => {\n const { minLength, maxLength } = params\n val = isNullOrUndefined(val) ? '' : val\n\n if (!isString(val)) return 'Value should be a text string'\n if (!isUndefined(minLength) && val.length < minLength)\n return `Value needs to be at least ${minLength} characters long`\n if (!isUndefined(maxLength) && val.length > maxLength)\n return `Value needs to be no more than ${maxLength} characters long`\n return true\n }\n\nexport const stringContains =\n (params: {\n match: string | RegExp\n message: string\n }): GenericValidateFunction<string> =>\n (val) => {\n const { match, message } = params\n\n if (!isString(val)) return 'Value should be a text string'\n if (!match) return true\n\n if (isString(match)) {\n return val.includes(match) ? true : message\n } else {\n return match.test(val) ? true : message\n }\n }\n\nexport const isUrl: GenericValidateFunction<string> = (value) => {\n if (VALID_HTTP_URL.test(value)) {\n return true\n }\n return 'Value is not a valid URL'\n}\n\nexport const isItemSelected: GenericValidateFunction<unknown[]> = (val) => {\n if (Array.isArray(val) && val.length > 0) {\n return true\n }\n return 'Value should have at least a single item selected'\n}\n","import type { Nullable, Optional } from '@speckle/shared'\nimport { useMutationObserver, useResizeObserver } from '@vueuse/core'\nimport { isUndefined } from 'lodash'\nimport { ref } from 'vue'\nimport type { Ref, ComputedRef } from 'vue'\n\n/**\n * Use this to calculate the number of hidden elements (e.g. user avatars) in a wrapping flex row that\n * is styled to only show the first row. For example, there are 12 users total, there's only space for 5,\n * and this composable will calculate the number of hidden ones to use for the \"+X\" label (+7 in the example)\n *\n * Note: The \"hidden\" items must wrap into another line, because we use their offset from the top of the parent\n * to check if they're hidden (compared to items in the 1st row)\n */\nexport function useWrappingContainerHiddenCount(params: {\n /**\n * Element to watch for any changes\n */\n elementToWatchForChanges: Ref<Nullable<HTMLElement>>\n /**\n * The element that actually contains the potentially visible/hidden items as direct children\n */\n itemContainer: Ref<Nullable<HTMLElement>>\n\n /**\n * Allows you to pause calculations conditionally\n */\n skipCalculation?: ComputedRef<boolean>\n\n /**\n * If true, will track resizing of 'elementToWatchForChanges'.\n * Default: false\n */\n trackResize?: boolean\n\n /**\n * If true, will track descendants being added/removed to 'elementToWatchForChanges'.\n * Default: true\n */\n trackMutations?: boolean\n}) {\n const {\n skipCalculation,\n elementToWatchForChanges,\n itemContainer,\n trackResize = false,\n trackMutations = true\n } = params || {}\n\n /**\n * Dynamically updated to show the number of items currently not visible in the container\n */\n const hiddenItemCount = ref(0)\n\n const recalculate = () => {\n const target = itemContainer.value\n if (skipCalculation?.value || !target) return\n\n const avatarElements = target.children\n\n /**\n * Comparing offset from parent to between all avatars to see when they break off into another line\n * and become invisible\n */\n let visibleCount = 0\n let totalCount = 0\n let firstElOffsetTop = undefined as Optional<number>\n for (const avatarEl of avatarElements) {\n const offsetTop = (avatarEl as HTMLElement).offsetTop\n if (isUndefined(firstElOffsetTop)) {\n firstElOffsetTop = offsetTop\n visibleCount += 1\n } else {\n if (offsetTop === firstElOffsetTop) {\n visibleCount += 1\n }\n }\n\n totalCount += 1\n }\n\n hiddenItemCount.value = totalCount - visibleCount\n }\n\n if (trackResize) {\n useResizeObserver(elementToWatchForChanges, recalculate)\n }\n\n if (trackMutations) {\n useMutationObserver(elementToWatchForChanges, recalculate, {\n childList: true,\n subtree: true\n })\n }\n\n return {\n hiddenItemCount\n }\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\nimport { isArray } from 'lodash'\nimport { computed, ref } from 'vue'\nimport type { Ref, ToRefs } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport { useWrappingContainerHiddenCount } from '~~/src/composables/layout/resize'\n\ntype GenericSelectValueType<T> = T | T[] | undefined\n\n/**\n * Common setup for FormSelectBase wrapping selector components\n */\nexport function useFormSelectChildInternals<T>(params: {\n props: ToRefs<{\n modelValue?: GenericSelectValueType<T>\n multiple?: boolean\n }>\n emit: {\n (e: 'update:modelValue', val: GenericSelectValueType<T>): void\n }\n /**\n * @see {useWrappingContainerHiddenCount()}\n */\n dynamicVisibility?: {\n elementToWatchForChanges: Ref<Nullable<HTMLElement>>\n itemContainer: Ref<Nullable<HTMLElement>>\n }\n}) {\n const { props, emit, dynamicVisibility } = params\n\n let hiddenItemCount: Ref<number>\n if (dynamicVisibility) {\n const { elementToWatchForChanges, itemContainer } = dynamicVisibility\n const hiddenCountData = useWrappingContainerHiddenCount({\n skipCalculation: computed(() => !props.multiple?.value),\n elementToWatchForChanges,\n itemContainer\n })\n hiddenItemCount = hiddenCountData.hiddenItemCount\n } else {\n hiddenItemCount = ref(0)\n }\n\n /**\n * Use this to get or set the v-model value of the select input in a proper way\n */\n const selectedValue = computed({\n get: (): GenericSelectValueType<T> => {\n const currentValue = props.modelValue?.value\n if (props.multiple?.value) {\n return isArray(currentValue) ? currentValue : []\n } else {\n return isArray(currentValue) ? undefined : currentValue\n }\n },\n set: (newVal: GenericSelectValueType<T>) => {\n if (props.multiple?.value && !isArray(newVal)) {\n console.warn('Attempting to set non-array value in selector w/ multiple=true')\n return\n } else if (!props.multiple?.value && isArray(newVal)) {\n console.warn('Attempting to set array value in selector w/ multiple=false')\n return\n }\n\n emit('update:modelValue', props.multiple?.value ? newVal || [] : newVal)\n }\n })\n\n const isArrayValue = (v: GenericSelectValueType<T>): v is T[] => isArray(v)\n const isMultiItemArrayValue = (v: GenericSelectValueType<T>): v is T[] =>\n isArray(v) && v.length > 1\n const firstItem = (v: NonNullable<GenericSelectValueType<T>>): T =>\n isArrayValue(v) ? v[0] : v\n\n return {\n selectedValue,\n hiddenSelectedItemCount: hiddenItemCount,\n isArrayValue,\n isMultiItemArrayValue,\n firstItem\n }\n}\n","<template>\n <div>\n <Listbox\n :key=\"forceUpdateKey\"\n v-model=\"wrappedValue\"\n :name=\"name\"\n :multiple=\"multiple\"\n :by=\"by\"\n :disabled=\"isDisabled\"\n as=\"div\"\n >\n <ListboxLabel\n class=\"block label text-foreground-2 mb-2\"\n :class=\"{ 'sr-only': !showLabel }\"\n >\n {{ label }}\n </ListboxLabel>\n <div :class=\"buttonsWrapperClasses\">\n <!-- <div class=\"relative flex\"> -->\n <ListboxButton ref=\"listboxButton\" v-slot=\"{ open }\" :class=\"buttonClasses\">\n <div class=\"flex items-center justify-between w-full\">\n <div class=\"block truncate grow text-left text-xs sm:text-sm\">\n <template\n v-if=\"!wrappedValue || (isArray(wrappedValue) && !wrappedValue.length)\"\n >\n <slot name=\"nothing-selected\">\n {{ placeholder ? placeholder : label }}\n </slot>\n </template>\n <template v-else>\n <slot name=\"something-selected\" :value=\"wrappedValue\">\n {{ simpleDisplayText(wrappedValue) }}\n </slot>\n </template>\n </div>\n <div class=\"pointer-events-none shrink-0 ml-1 flex items-center space-x-2\">\n <ExclamationCircleIcon\n v-if=\"errorMessage\"\n class=\"h-4 w-4 text-danger\"\n aria-hidden=\"true\"\n />\n <div\n v-else-if=\"showRequired\"\n class=\"text-4xl text-danger opacity-50 h-4 w-4 leading-6\"\n >\n *\n </div>\n <ChevronUpIcon\n v-if=\"open\"\n class=\"h-4 w-4 text-foreground\"\n aria-hidden=\"true\"\n />\n <ChevronDownIcon\n v-else\n class=\"h-4 w-4 text-foreground\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n </ListboxButton>\n <!-- </div> -->\n <!-- Clear Button -->\n <button\n v-if=\"renderClearButton\"\n v-tippy=\"'Clear'\"\n :class=\"clearButtonClasses\"\n :disabled=\"disabled\"\n @click=\"clearValue()\"\n >\n <XMarkIcon class=\"w-3 h-3\" />\n </button>\n <Transition\n v-if=\"isMounted\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <Teleport to=\"body\" :disabled=\"!mountMenuOnBody\">\n <ListboxOptions\n ref=\"menuEl\"\n :class=\"listboxOptionsClasses\"\n :style=\"listboxOptionsStyle\"\n @focus=\"searchInput?.focus()\"\n >\n <label v-if=\"hasSearch\" class=\"flex flex-col mx-1 mb-1\">\n <span class=\"sr-only label text-foreground\">Search</span>\n <div class=\"relative\">\n <div\n class=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2\"\n >\n <MagnifyingGlassIcon class=\"h-5 w-5 text-foreground\" />\n </div>\n <input\n ref=\"searchInput\"\n v-model=\"searchValue\"\n type=\"text\"\n class=\"pl-9 w-full border-0 bg-foundation-page rounded placeholder:font-normal normal placeholder:text-foreground-2 focus:outline-none focus:ring-1 focus:border-outline-1 focus:ring-outline-1\"\n :placeholder=\"searchPlaceholder\"\n @keydown.stop\n />\n </div>\n </label>\n <div\n class=\"overflow-auto simple-scrollbar\"\n :class=\"[hasSearch ? 'max-h-52' : 'max-h-40']\"\n >\n <div v-if=\"isAsyncSearchMode && isAsyncLoading\" class=\"px-1\">\n <CommonLoadingBar :loading=\"true\" />\n </div>\n <div v-else-if=\"isAsyncSearchMode && !currentItems.length\">\n <slot name=\"nothing-found\">\n <div class=\"text-foreground-2 text-center\">Nothing found 🤷‍♂️</div>\n </slot>\n </div>\n <template v-if=\"!isAsyncSearchMode || !isAsyncLoading\">\n <ListboxOption\n v-for=\"item in finalItems\"\n :key=\"itemKey(item)\"\n v-slot=\"{\n active,\n selected\n }: {\n active: boolean,\n selected: boolean\n }\"\n :value=\"item\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n <li\n :class=\"\n listboxOptionClasses({\n active,\n disabled: disabledItemPredicate?.(item) || false\n })\n \"\n >\n <span :class=\"['block truncate']\">\n <slot\n name=\"option\"\n :item=\"item\"\n :active=\"active\"\n :selected=\"selected\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n {{ simpleDisplayText(item) }}\n </slot>\n </span>\n\n <span\n v-if=\"!hideCheckmarks && selected\"\n :class=\"[\n active ? 'text-primary' : 'text-foreground',\n 'absolute inset-y-0 right-0 flex items-center pr-4'\n ]\"\n >\n <CheckIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </span>\n </li>\n </ListboxOption>\n </template>\n </div>\n </ListboxOptions>\n </Teleport>\n </Transition>\n </div>\n </Listbox>\n <p\n v-if=\"helpTipId\"\n :id=\"helpTipId\"\n class=\"mt-2 text-xs sm:text-sm\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script\n setup\n lang=\"ts\"\n generic=\"SingleItem extends Record<string, unknown> | string | number\"\n>\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport {\n Listbox,\n ListboxButton,\n ListboxOption,\n ListboxOptions,\n ListboxLabel\n} from '@headlessui/vue'\nimport {\n ChevronDownIcon,\n CheckIcon,\n ChevronUpIcon,\n MagnifyingGlassIcon,\n XMarkIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/24/solid'\nimport { debounce, isArray, isObjectLike } from 'lodash'\nimport type { CSSProperties, PropType, Ref } from 'vue'\nimport { computed, onMounted, ref, unref, watch } from 'vue'\nimport type { MaybeAsync, Nullable, Optional } from '@speckle/shared'\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { nanoid } from 'nanoid'\nimport CommonLoadingBar from '~~/src/components/common/loading/Bar.vue'\nimport { directive as vTippy } from 'vue-tippy'\nimport { useElementBounding, useMounted, useIntersectionObserver } from '@vueuse/core'\n\ntype ButtonStyle = 'base' | 'simple' | 'tinted'\ntype ValueType = SingleItem | SingleItem[] | undefined\n\nconst isObjectLikeType = (v: unknown): v is Record<string, unknown> => isObjectLike(v)\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n multiple: {\n type: Boolean,\n default: false\n },\n items: {\n type: Array as PropType<SingleItem[]>,\n default: () => []\n },\n modelValue: {\n type: [Object, Array, String] as PropType<ValueType>,\n default: undefined\n },\n /**\n * Whether to enable the search bar. You must also set one of the following:\n * * filterPredicate - to allow filtering passed in `items` based on search bar\n * * getSearchResults - to allow asynchronously loading items from server (props.items no longer required in this case,\n * but can be used to prefill initial values)\n */\n search: {\n type: Boolean,\n default: false\n },\n /**\n * If search=true and this is set, you can use this to filter passed in items based on whatever\n * the user enters in the search bar\n */\n filterPredicate: {\n type: Function as PropType<\n Optional<(item: SingleItem, searchString: string) => boolean>\n >,\n default: undefined\n },\n /**\n * Set this to disable certain items in the list\n */\n disabledItemPredicate: {\n type: Function as PropType<Optional<(item: SingleItem) => boolean>>,\n default: undefined\n },\n /**\n * If search=true and this is set, you can use this to load data asynchronously depending\n * on the search query\n */\n getSearchResults: {\n type: Function as PropType<\n Optional<(searchString: string) => MaybeAsync<SingleItem[]>>\n >,\n default: undefined\n },\n searchPlaceholder: {\n type: String,\n default: 'Search'\n },\n /**\n * Label is required at the very least for screen-readers\n */\n label: {\n type: String,\n required: true\n },\n /**\n * Optional text that replaces the label as the placeholder when set.\n */\n placeholder: {\n type: String\n },\n /**\n * Whether to show the label visually\n */\n showLabel: {\n type: Boolean,\n default: false\n },\n name: {\n type: String,\n required: true\n },\n /**\n * Objects will be compared by the values in the specified prop\n */\n by: {\n type: String,\n required: false\n },\n disabled: {\n type: Boolean as PropType<Optional<boolean>>,\n default: false\n },\n buttonStyle: {\n type: String as PropType<Optional<ButtonStyle>>,\n default: 'base'\n },\n hideCheckmarks: {\n type: Boolean as PropType<Optional<boolean>>,\n default: false\n },\n allowUnset: {\n type: Boolean as PropType<Optional<boolean>>,\n default: true\n },\n clearable: {\n type: Boolean,\n default: false\n },\n /**\n * Validation stuff\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<ValueType>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to trigger validation whenever the value changes\n */\n validateOnValueUpdate: {\n type: Boolean,\n default: false\n },\n /**\n * Will replace the generic \"Value\" text with the name of the input in error messages\n */\n useLabelInErrors: {\n type: Boolean,\n default: true\n },\n /**\n * Optional help text\n */\n help: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n fixedHeight: {\n type: Boolean,\n default: false\n },\n /**\n * By default component holds its own internal value state so that even if you don't have it tied up to a real `modelValue` ref somewhere\n * it knows its internal state and can report it on form submits.\n *\n * If you set this to true, its only going to rely on `modelValue` as its primary source of truth so that you can reject updates etc.\n */\n fullyControlValue: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to mount the menu on the body instead of inside the component. Useful when select box is mounted within\n * dialog windows and the menu causes unnecessary overflow.\n */\n mountMenuOnBody: {\n type: Boolean,\n default: false\n }\n})\n\nconst { value, errorMessage: error } = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n initialValue: props.modelValue as ValueType\n})\n\nconst isMounted = useMounted()\n\nconst searchInput = ref(null as Nullable<HTMLInputElement>)\nconst menuEl = ref(null as Nullable<{ el: Nullable<HTMLElement> }>)\nconst listboxButton = ref(null as Nullable<{ el: Nullable<HTMLButtonElement> }>)\nconst searchValue = ref('')\nconst currentItems = ref([]) as Ref<SingleItem[]>\nconst isAsyncLoading = ref(false)\nconst forceUpdateKey = ref(1)\nconst internalHelpTipId = ref(nanoid())\n\nconst listboxButtonBounding = useElementBounding(\n computed(() => listboxButton.value?.el),\n { windowResize: true, windowScroll: true, immediate: true }\n)\n\nuseIntersectionObserver(\n computed(() => menuEl.value?.el),\n ([{ isIntersecting }]) => {\n if (isIntersecting && props.mountMenuOnBody) {\n listboxButtonBounding.update()\n }\n }\n)\n\nconst title = computed(() => unref(props.label) || unref(props.name))\nconst errorMessage = computed(() => {\n const base = error.value\n if (!base || !unref(props.useLabelInErrors)) return base\n return base.replace('Value', title.value)\n})\nconst helpTip = computed(() => errorMessage.value || unref(props.help))\nconst hasHelpTip = computed(() => !!helpTip.value)\nconst helpTipId = computed(() =>\n hasHelpTip.value ? `${unref(props.name)}-${internalHelpTipId.value}` : undefined\n)\nconst helpTipClasses = computed((): string =>\n error.value ? 'text-danger' : 'text-foreground-2'\n)\n\nconst renderClearButton = computed(\n () => props.buttonStyle !== 'simple' && props.clearable && !props.disabled\n)\n\nconst buttonsWrapperClasses = computed(() => {\n const classParts: string[] = ['relative flex group']\n\n if (error.value) {\n classParts.push('hover:shadow rounded-md')\n classParts.push('text-danger-darker focus:border-danger focus:ring-danger')\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('outline outline-2 outline-danger')\n }\n } else if (props.buttonStyle !== 'simple') {\n classParts.push('hover:shadow rounded-md')\n classParts.push('outline outline-2 outline-primary-muted')\n }\n\n if (props.fixedHeight) {\n classParts.push('h-8')\n }\n\n return classParts.join(' ')\n})\n\nconst commonButtonClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.buttonStyle !== 'simple') {\n // classParts.push('group-hover:shadow')\n // classParts.push('outline outline-2 outline-primary-muted ')\n classParts.push(\n isDisabled.value ? 'bg-foundation-disabled text-foreground-disabled' : ''\n )\n }\n\n if (isDisabled.value) classParts.push('cursor-not-allowed')\n\n return classParts.join(' ')\n})\n\nconst clearButtonClasses = computed(() => {\n const classParts = [\n 'relative z-[1]',\n 'flex items-center justify-center text-center shrink-0',\n 'rounded-r-md overflow-hidden transition-all',\n 'text-foreground',\n hasValueSelected.value ? `w-6 ${commonButtonClasses.value}` : 'w-0'\n ]\n\n if (!isDisabled.value) {\n classParts.push(\n 'hover:bg-primary hover:text-foreground-on-primary dark:text-foreground-on-primary'\n )\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-outline-3')\n } else {\n classParts.push('bg-primary-muted')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst buttonClasses = computed(() => {\n const classParts = [\n 'relative z-[2]',\n 'normal rounded-md cursor-pointer transition truncate flex-1',\n 'flex items-center',\n commonButtonClasses.value\n ]\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('py-2 px-3')\n\n if (!isDisabled.value) {\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-foundation-page text-foreground')\n } else {\n classParts.push('bg-foundation text-foreground')\n }\n }\n }\n\n if (renderClearButton.value && hasValueSelected.value) {\n classParts.push('rounded-r-none')\n }\n\n return classParts.join(' ')\n})\n\nconst hasSearch = computed(\n () => !!(props.search && (props.filterPredicate || props.getSearchResults))\n)\nconst isAsyncSearchMode = computed(() => hasSearch.value && props.getSearchResults)\nconst isDisabled = computed(\n () => props.disabled || (!props.items.length && !isAsyncSearchMode.value)\n)\n\nconst wrappedValue = computed({\n get: () => {\n const currentValue = value.value\n if (props.multiple) {\n return isArray(currentValue) ? currentValue : []\n } else {\n return isArray(currentValue) ? undefined : currentValue\n }\n },\n set: (newVal) => {\n if (props.multiple && !isArray(newVal)) {\n console.warn('Attempting to set non-array value in selector w/ multiple=true')\n return\n } else if (!props.multiple && isArray(newVal)) {\n console.warn('Attempting to set array value in selector w/ multiple=false')\n return\n }\n\n let finalValue: typeof value.value\n if (props.multiple) {\n finalValue = newVal || []\n } else {\n const currentVal = value.value\n const isUnset =\n props.allowUnset &&\n currentVal &&\n newVal &&\n itemKey(currentVal as SingleItem) === itemKey(newVal as SingleItem)\n finalValue = isUnset ? undefined : newVal\n }\n\n if (props.fullyControlValue) {\n // Not setting value.value, cause then we don't give a chance for the parent\n // component to reject the update\n emit('update:modelValue', finalValue)\n } else {\n value.value = finalValue\n }\n\n // hacky, but there's no other way to force ListBox to re-read the modelValue prop which\n // we need in case the update was rejected and ListBox still thinks the value is the one\n // that was clicked on\n forceUpdateKey.value += 1\n }\n})\n\nconst hasValueSelected = computed(() => {\n if (props.multiple && isArray(wrappedValue.value))\n return wrappedValue.value.length !== 0\n else return !!wrappedValue.value\n})\n\nconst clearValue = () => {\n if (props.multiple) wrappedValue.value = []\n else wrappedValue.value = undefined\n}\n\nconst finalItems = computed(() => {\n const searchVal = searchValue.value\n if (!hasSearch.value || !searchVal?.length) return currentItems.value\n\n if (props.filterPredicate) {\n return currentItems.value.filter(\n (i) => props.filterPredicate?.(i, searchVal) || false\n )\n }\n\n return currentItems.value\n})\n\nconst listboxOptionsClasses = computed(() => {\n const classParts = [\n 'rounded-md bg-foundation-2 py-1 label label--light outline outline-2 outline-primary-muted focus:outline-none shadow mt-1 '\n ]\n\n if (props.mountMenuOnBody) {\n classParts.push('fixed z-50')\n } else {\n classParts.push('absolute top-[100%] w-full z-10')\n }\n\n return classParts.join(' ')\n})\n\nconst listboxOptionsStyle = computed(() => {\n const style: CSSProperties = {}\n\n if (props.mountMenuOnBody) {\n const top = listboxButtonBounding.top.value\n const left = listboxButtonBounding.left.value\n const width = listboxButtonBounding.width.value\n const height = listboxButtonBounding.height.value\n\n style.top = `${top + height}px`\n style.left = `${left}px`\n style.width = `${width}px`\n }\n\n return style\n})\n\nconst simpleDisplayText = (v: ValueType) => JSON.stringify(v)\nconst itemKey = (v: SingleItem): string | number => {\n if (isObjectLikeType(v)) {\n return v[props.by || 'id'] as string\n } else {\n return v\n }\n}\n\nconst triggerSearch = async () => {\n if (!isAsyncSearchMode.value || !props.getSearchResults) return\n\n isAsyncLoading.value = true\n try {\n currentItems.value = await props.getSearchResults(searchValue.value)\n } finally {\n isAsyncLoading.value = false\n }\n}\nconst debouncedSearch = debounce(triggerSearch, 1000)\n\nconst listboxOptionClasses = (params: { active: boolean; disabled: boolean }) => {\n const { active, disabled } = params || {}\n const { hideCheckmarks } = props\n\n const classParts = [\n 'relative transition cursor-pointer select-none py-1.5 pl-3',\n !hideCheckmarks ? 'pr-9' : ''\n ]\n\n if (disabled) {\n classParts.push('opacity-50 cursor-not-allowed')\n } else {\n classParts.push(active ? 'text-primary' : 'text-foreground')\n }\n\n return classParts.join(' ')\n}\n\nwatch(\n () => props.items,\n (newItems) => {\n currentItems.value = newItems.slice()\n },\n { immediate: true }\n)\n\nwatch(searchValue, () => {\n if (!isAsyncSearchMode.value) return\n debouncedSearch()\n})\n\nonMounted(() => {\n if (isAsyncSearchMode.value && !props.items.length) {\n triggerSearch()\n }\n})\n\ndefineExpose({ triggerSearch })\n</script>\n","<template>\n <FormSelectBase\n v-model=\"selectedValue\"\n :multiple=\"multiple\"\n :items=\"items ?? SourceApps\"\n :search=\"search\"\n :search-placeholder=\"searchPlaceholder\"\n :label=\"label\"\n :show-label=\"showLabel\"\n :name=\"name || 'sourceApps'\"\n :filter-predicate=\"searchFilterPredicate\"\n :clearable=\"clearable\"\n :help=\"help\"\n by=\"name\"\n >\n <template #nothing-selected>\n <template v-if=\"selectorPlaceholder\">\n {{ selectorPlaceholder }}\n </template>\n <template v-else>\n {{ multiple ? 'Select apps' : 'Select an app' }}\n </template>\n </template>\n <template #something-selected=\"{ value }\">\n <template v-if=\"isMultiItemArrayValue(value)\">\n <div ref=\"elementToWatchForChanges\" class=\"flex items-center space-x-0.5 h-5\">\n <div\n ref=\"itemContainer\"\n class=\"flex flex-wrap overflow-hidden space-x-0.5 h-5\"\n >\n <SourceAppBadge v-for=\"item in value\" :key=\"item.name\" :source-app=\"item\" />\n </div>\n <div v-if=\"hiddenSelectedItemCount > 0\" class=\"text-foreground-2 normal\">\n +{{ hiddenSelectedItemCount }}\n </div>\n </div>\n </template>\n <template v-else>\n <div class=\"flex items-center\">\n <div\n class=\"h-2 w-2 rounded-full mr-2\"\n :style=\"{ backgroundColor: firstItem(value).bgColor }\"\n />\n <span class=\"truncate\">{{ firstItem(value).name }}</span>\n </div>\n </template>\n </template>\n <template #option=\"{ item }\">\n <div class=\"flex items-center\">\n <div\n class=\"h-2 w-2 rounded-full mr-2\"\n :style=\"{ backgroundColor: item.bgColor }\"\n />\n <span class=\"truncate\">{{ item.name }}</span>\n </div>\n </template>\n </FormSelectBase>\n</template>\n<script setup lang=\"ts\">\nimport type { Nullable, Optional, SourceAppDefinition } from '@speckle/shared'\nimport { SourceApps } from '@speckle/shared'\nimport { ref, toRefs } from 'vue'\nimport type { PropType } from 'vue'\nimport { useFormSelectChildInternals } from '~~/src/composables/form/select'\nimport FormSelectBase from '~~/src/components/form/select/Base.vue'\nimport SourceAppBadge from '~~/src/components/SourceAppBadge.vue'\n\ntype ValueType = SourceAppDefinition | SourceAppDefinition[] | undefined\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n /**\n * Whether to allow selecting multiple source apps\n */\n multiple: {\n type: Boolean,\n default: false\n },\n modelValue: {\n type: [Object, Array] as PropType<ValueType>,\n default: undefined\n },\n /**\n * Whether to allow filtering source apps through a search box\n */\n search: {\n type: Boolean,\n default: false\n },\n /**\n * Search placeholder text\n */\n searchPlaceholder: {\n type: String,\n default: 'Search apps'\n },\n selectorPlaceholder: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Label is required at the very least for screen-readers\n */\n label: {\n type: String,\n required: true\n },\n /**\n * Whether to show the label visually\n */\n showLabel: {\n type: Boolean,\n default: false\n },\n name: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Control source apps to show. If left undefined, will show all available options.\n */\n items: {\n type: Array as PropType<Optional<SourceAppDefinition[]>>,\n default: undefined\n },\n clearable: {\n type: Boolean\n },\n help: {\n type: String\n }\n})\n\nconst elementToWatchForChanges = ref(null as Nullable<HTMLElement>)\nconst itemContainer = ref(null as Nullable<HTMLElement>)\n\nconst { selectedValue, hiddenSelectedItemCount, isMultiItemArrayValue, firstItem } =\n useFormSelectChildInternals<SourceAppDefinition>({\n props: toRefs(props),\n emit,\n dynamicVisibility: { elementToWatchForChanges, itemContainer }\n })\n\nconst searchFilterPredicate = (i: SourceAppDefinition, search: string) =>\n i.name.toLocaleLowerCase().includes(search.toLocaleLowerCase())\n</script>\n","<template>\n <FormSelectBase\n v-model=\"selectedValue\"\n :multiple=\"multiple\"\n :items=\"items\"\n :label=\"label\"\n :name=\"name\"\n :help=\"help\"\n :rules=\"rules\"\n :by=\"by\"\n >\n <template #something-selected=\"{ value }\">\n <ul class=\"flex flex-wrap gap-1.5 text-xs\">\n <li v-for=\"item in isArrayValue(value) ? value : [value]\" :key=\"item[by]\">\n <CommonBadge\n size=\"lg\"\n :clickable-icon=\"true\"\n :icon-left=\"XMarkIcon\"\n @click-icon.stop=\"deselectItem(item)\"\n >\n {{ item.text }}\n </CommonBadge>\n </li>\n </ul>\n </template>\n <template #option=\"{ item }\">\n {{ item.text }}\n </template>\n </FormSelectBase>\n</template>\n\n<script setup lang=\"ts\">\n// Vue components don't support generic props, so having to rely on any\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport { toRefs } from 'vue'\nimport FormSelectBase from '~~/src/components/form/select/Base.vue'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\nimport { useFormSelectChildInternals } from '~~/src/composables/form/select'\nimport { XMarkIcon } from '@heroicons/vue/24/solid'\n\ntype SingleItem = any\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n items: null,\n label: null,\n name: null,\n help: null,\n modelValue: null,\n multiple: { type: Boolean },\n rules: null,\n by: null\n})\n\nconst { selectedValue, isArrayValue } = useFormSelectChildInternals<SingleItem>({\n props: toRefs(props),\n emit\n})\n\nconst deselectItem = (item: SingleItem) => {\n if (isArrayValue(selectedValue.value)) {\n selectedValue.value = selectedValue.value.filter((i) => i.id !== item.id)\n } else {\n selectedValue.value = undefined\n }\n}\n</script>\n","<template>\n <div class=\"flex items-center\">\n <HeadlessSwitch\n v-model=\"enabled\"\n class=\"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary\"\n :class=\"{ 'bg-primary': enabled, 'bg-primary-muted': !enabled }\"\n >\n <div class=\"absolute inset-0 flex items-center gap-2 px-1 text-white\">\n <CheckIcon\n class=\"h-5 w-5 drop-shadow-md\"\n :class=\"icons ? 'opacity-100' : 'opacity-0'\"\n />\n <XMarkIcon\n class=\"h-5 w-5 drop-shadow-md\"\n :class=\"icons ? 'opacity-100' : 'opacity-0'\"\n />\n </div>\n <span\n class=\"scale-95 pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200\"\n :class=\"{ 'translate-x-5': enabled, 'translate-x-0': !enabled }\"\n ></span>\n </HeadlessSwitch>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Switch as HeadlessSwitch } from '@headlessui/vue'\nimport { CheckIcon, XMarkIcon } from '@heroicons/vue/24/solid'\n\ndefineProps({\n icons: { type: Boolean }\n})\n\nconst enabled = defineModel<boolean>()\n</script>\n","<template>\n <div class=\"relative group bg-foundation-page p-2 rounded-lg pr-12\">\n <div\n v-if=\"isMultiline\"\n class=\"relative z-10 text-xs sm:text-sm text-foreground font-mono break-all p-2 pl-3 max-h-[4.8rem] simple-scrollbar overflow-y-auto\"\n @keypress=\"keyboardClick(selectAllText)\"\n >\n {{ value }}\n </div>\n <FormTextInput\n v-else\n color=\"transparent\"\n name=\"contentInput\"\n readonly\n :model-value=\"value\"\n class=\"relative z-10 text-sm text-foreground font-mono\"\n />\n <div class=\"absolute inset-0 right-2 flex justify-end items-center\">\n <FormButton\n color=\"invert\"\n size=\"sm\"\n :icon-left=\"copied ? ClipboardDocumentCheckIcon : ClipboardDocumentIcon\"\n hide-text\n @click=\"handleCopy\"\n ></FormButton>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useClipboard } from '@vueuse/core'\nimport {\n ClipboardDocumentIcon,\n ClipboardDocumentCheckIcon\n} from '@heroicons/vue/24/outline'\nimport { FormTextInput, FormButton } from '~~/src/lib'\nimport { ref } from 'vue'\nimport { keyboardClick } from '~~/src/helpers/global/accessibility'\n\ntype Props = {\n value: string\n isMultiline?: boolean\n rows?: number\n}\n\nconst props = defineProps({\n value: null,\n isMultiline: { type: Boolean, default: false },\n rows: null\n})\n\nconst emit = defineEmits([\"copy\"])\n\nconst { copy } = useClipboard({ legacy: true })\n\nconst copied = ref(false)\n\nconst handleCopy = async () => {\n if (props.value) {\n await copy(props.value)\n copied.value = true\n emit('copy', props.value)\n\n setTimeout(() => {\n copied.value = false\n }, 2000)\n }\n}\n\nconst selectAllText = (event: Event) => {\n const textElement = event.target as HTMLElement\n\n const selection = window.getSelection()\n if (selection) {\n const range = document.createRange()\n range.selectNodeContents(textElement)\n selection.removeAllRanges()\n selection.addRange(range)\n }\n}\n</script>\n","import { getClientOperatingSystem, OperatingSystem } from '@speckle/shared'\n\nexport enum ModifierKeys {\n CtrlOrCmd = 'cmd-or-ctrl',\n AltOrOpt = 'alt-or-opt',\n Shift = 'shift'\n}\n\nexport const clientOs = getClientOperatingSystem()\n\nexport const ModifierKeyTitles: Record<ModifierKeys, string> = {\n [ModifierKeys.CtrlOrCmd]: clientOs === OperatingSystem.Mac ? 'Cmd' : 'Ctrl',\n [ModifierKeys.AltOrOpt]: clientOs === OperatingSystem.Mac ? 'Opt' : 'Alt',\n [ModifierKeys.Shift]: 'Shift'\n}\n\nexport function getKeyboardShortcutTitle(keys: Array<string | ModifierKeys>) {\n const isModifierKey = (k: string): k is ModifierKeys =>\n (Object.values(ModifierKeys) as string[]).includes(k)\n\n return keys.map((v) => (isModifierKey(v) ? ModifierKeyTitles[v] : v)).join('+')\n}\n","import { onKeyDown } from '@vueuse/core'\nimport { OperatingSystem } from '@speckle/shared'\nimport { clientOs, ModifierKeys } from '~~/src/helpers/form/input'\nimport { computed, ref } from 'vue'\nimport type { Ref } from 'vue'\n\n/**\n * onKeyDown wrapper that also checks for modifier keys being pressed\n */\nexport function onKeyboardShortcut(\n modifiers: ModifierKeys[],\n ...args: Parameters<typeof onKeyDown>\n) {\n onKeyDown(\n args[0],\n (e) => {\n const isAltOrOpt = e.getModifierState('Alt')\n const isCtrlOrCmd =\n clientOs === OperatingSystem.Mac\n ? e.getModifierState('Meta')\n : e.getModifierState('Control')\n const isShift = e.getModifierState('Shift')\n\n for (const modifier of modifiers) {\n switch (modifier) {\n case ModifierKeys.CtrlOrCmd:\n if (!isCtrlOrCmd) return\n break\n case ModifierKeys.AltOrOpt:\n if (!isAltOrOpt) return\n break\n case ModifierKeys.Shift:\n if (!isShift) return\n break\n }\n }\n\n args[1](e)\n },\n args[2]\n )\n}\n\n/**\n * To support group checkboxes, the checkbox v-model API is a bit confusing: The value is `true` or `undefined`\n * not `true` or `false`.\n *\n * To simplify working with single checkboxes, you can use the model returned from this composable\n * as the model and `isChecked` as a helpful wrapper that allows you to deal with boolean values only\n */\nexport function useFormCheckboxModel(\n options?: Partial<{\n model: Ref<true | undefined>\n }>\n) {\n const model = options?.model || ref<true | undefined>()\n const isChecked = computed({\n get: () => !!model.value,\n set: (newVal) => (model.value = newVal ? true : undefined)\n })\n\n return { model, isChecked }\n}\n","<template>\n <TransitionRoot as=\"template\" :show=\"open\">\n <Dialog as=\"div\" class=\"relative z-40\" @close=\"onClose\">\n <TransitionChild\n as=\"template\"\n enter=\"ease-out duration-300\"\n enter-from=\"opacity-0\"\n enter-to=\"opacity-100\"\n leave=\"ease-in duration-200\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n class=\"fixed inset-0 bg-neutral-100/70 dark:bg-neutral-900/70 transition-opacity backdrop-blur-xs\"\n />\n </TransitionChild>\n\n <div class=\"fixed inset-0 z-10 h-[100dvh] w-screen\">\n <div class=\"flex justify-center items-center h-full w-full p-4 sm:p-0\">\n <TransitionChild\n as=\"template\"\n enter=\"ease-out duration-300\"\n enter-from=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n enter-to=\"opacity-100 translate-y-0 sm:scale-100\"\n leave=\"ease-in duration-200\"\n leave-from=\"opacity-100 translate-y-0 sm:scale-100\"\n leave-to=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n @after-leave=\"$emit('fully-closed')\"\n >\n <DialogPanel\n :class=\"[\n 'transform rounded-lg text-foreground overflow-hidden bg-foundation text-left shadow-xl transition-all flex flex-col max-h-[90vh]',\n widthClasses\n ]\"\n :as=\"isForm ? 'form' : 'div'\"\n @submit.prevent=\"onSubmit\"\n >\n <div :class=\"scrolledFromTop && 'relative z-20 shadow-lg'\">\n <div\n v-if=\"hasTitle\"\n class=\"flex items-center justify-start rounded-t-lg shrink-0 min-h-[2rem] sm:min-h-[4rem] py-2 px-4 sm:px-8 truncate text-lg sm:text-2xl font-bold\"\n >\n <div class=\"w-full truncate pr-12\">\n {{ title }}\n <slot name=\"header\"></slot>\n </div>\n </div>\n </div>\n\n <button\n v-if=\"!hideCloser\"\n class=\"absolute z-20 bg-foundation rounded-full p-1\"\n :class=\"hasTitle ? 'top-2 right-3 sm:top-4' : 'right-4 top-3'\"\n @click=\"open = false\"\n >\n <XMarkIcon class=\"h-5 sm:h-6 w-5 sm:w-6\" />\n </button>\n <div\n class=\"flex-1 simple-scrollbar overflow-y-auto\"\n :class=\"hasTitle ? 'p-3 sm:py-6 sm:px-8' : 'p-6 pt-10 sm:p-10'\"\n @scroll=\"onScroll\"\n >\n <slot>Put your content here!</slot>\n </div>\n <div\n v-if=\"hasButtons\"\n class=\"relative z-50 flex px-4 py-2 sm:py-4 sm:px-6 gap-2 shrink-0 bg-foundation\"\n :class=\"!scrolledToBottom && 'shadow-t'\"\n >\n <template v-if=\"buttons\">\n <FormButton\n v-for=\"(button, index) in buttons\"\n :key=\"index\"\n v-bind=\"button.props\"\n :disabled=\"button.disabled\"\n :type=\"button.submit && 'submit'\"\n @click=\"button.onClick\"\n >\n {{ button.text }}\n </FormButton>\n </template>\n <template v-else>\n <slot name=\"buttons\" />\n </template>\n </div>\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n</template>\n<script setup lang=\"ts\">\nimport { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'\nimport { FormButton } from '~~/src/lib'\nimport { XMarkIcon } from '@heroicons/vue/24/outline'\nimport { computed, ref, useSlots } from 'vue'\nimport { throttle } from 'lodash'\n\ntype MaxWidthValue = 'sm' | 'md' | 'lg' | 'xl'\n\nconst emit = defineEmits([\"update:open\", \"fully-closed\"])\n\nconst props = defineProps({\n open: { type: Boolean },\n maxWidth: null,\n hideCloser: { type: Boolean },\n preventCloseOnClickOutside: { type: Boolean },\n title: null,\n buttons: null,\n onSubmit: { type: Function }\n})\n\nconst slots = useSlots()\n\nconst scrolledFromTop = ref(false)\nconst scrolledToBottom = ref(true)\n\nconst isForm = computed(() => !!props.onSubmit)\nconst hasButtons = computed(() => props.buttons || slots.buttons)\nconst hasTitle = computed(() => props.title || slots.header)\n\nconst open = computed({\n get: () => props.open,\n set: (newVal) => emit('update:open', newVal)\n})\n\nconst maxWidthWeight = computed(() => {\n switch (props.maxWidth) {\n case 'sm':\n return 0\n case 'md':\n return 1\n case 'lg':\n return 2\n case 'xl':\n return 3\n default:\n return 10000\n }\n})\n\nconst widthClasses = computed(() => {\n const classParts: string[] = ['w-full', 'sm:w-full sm:max-w-2xl']\n\n if (maxWidthWeight.value >= 1) {\n classParts.push('md:max-w-2xl')\n }\n if (maxWidthWeight.value >= 2) {\n classParts.push('lg:max-w-4xl')\n }\n if (maxWidthWeight.value >= 3) {\n classParts.push('xl:max-w-6xl')\n }\n if (maxWidthWeight.value >= 4) {\n classParts.push('2xl:max-w-7xl')\n }\n\n return classParts.join(' ')\n})\n\nconst onClose = () => {\n if (props.preventCloseOnClickOutside) return\n open.value = false\n}\n\nconst onScroll = throttle((e: Event) => {\n const target = e.target as HTMLElement\n const { scrollTop, offsetHeight, scrollHeight } = target\n scrolledFromTop.value = scrollTop > 0\n scrolledToBottom.value = scrollTop + offsetHeight >= scrollHeight\n}, 60)\n</script>\n","<template>\n <div\n class=\"flex flex-col border-primary-muted\"\n :class=\"{\n 'border-t': borderT,\n 'border-b': borderB,\n 'relative z-10': isExpanded\n }\"\n >\n <div\n class=\"flex justify-between items-center gap-4 sm:gap-8 py-3 sm:py-4 px-2\"\n :class=\"backgroundClass\"\n tabindex=\"0\"\n v-on=\"\n !button && !alwaysOpen\n ? {\n click: toggleExpansion,\n keypress: keyboardClick(toggleExpansion)\n }\n : {}\n \"\n >\n <div\n class=\"text-sm sm:text-base font-bold flex items-center gap-1 sm:gap-2 select-none\"\n :class=\"titleClasses\"\n >\n <div class=\"h-4 sm:h-5 w-4 sm:w-5 empty:h-0 empty:w-0\">\n <slot name=\"icon\"></slot>\n </div>\n <span>{{ title }}</span>\n </div>\n <div>\n <ChevronDownIcon\n v-if=\"!button && !alwaysOpen\"\n class=\"w-4 h-4 sm:w-5 sm:h-5 transition-all duration-400\"\n :class=\"isExpanded && 'rotate-180'\"\n />\n <FormButton\n v-if=\"button\"\n size=\"sm\"\n :to=\"button.expandContent ? undefined : button.to\"\n :color=\"button.expandContent && isExpanded ? 'invert' : button.color\"\n :icon-right=\"\n button.expandContent && isExpanded ? undefined : button.iconRight\n \"\n @click=\"button?.onClick\"\n v-on=\"button?.expandContent ? { click: toggleExpansion } : {}\"\n >\n {{ button.expandContent && isExpanded ? 'Cancel' : button.text }}\n </FormButton>\n </div>\n </div>\n <div\n class=\"transition-all duration-700 overflow-hidden\"\n :class=\"[\n allowOverflow && isExpanded ? '!overflow-visible' : '',\n isExpanded ? 'mb-3 mt-1' : '',\n !button && !alwaysOpen ? 'cursor-pointer hover:bg-foundation' : ''\n ]\"\n :style=\"\n alwaysOpen\n ? 'max-height: none;'\n : `max-height: ${isExpanded ? contentHeight + 'px' : '0px'}`\n \"\n >\n <template v-if=\"props.lazyLoad\">\n <div\n v-if=\"isExpanded || props.alwaysOpen\"\n ref=\"content\"\n class=\"rounded-md text-sm pb-3 px-2 mt-1\"\n >\n <slot>Panel contents</slot>\n </div>\n </template>\n\n <template v-else>\n <div ref=\"content\" class=\"rounded-md text-sm pb-3 px-2 mt-1\">\n <slot>Panel contents</slot>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, unref, computed, nextTick } from 'vue'\nimport type { Ref } from 'vue'\nimport { ChevronDownIcon } from '@heroicons/vue/24/outline'\nimport { FormButton } from '~~/src/lib'\nimport { keyboardClick } from '~~/src/helpers/global/accessibility'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype TitleColor = 'default' | 'danger' | 'warning' | 'success' | 'secondary' | 'info'\n\ntype FormButtonColor =\n | 'default'\n | 'invert'\n | 'danger'\n | 'warning'\n | 'success'\n | 'card'\n | 'secondary'\n | 'info'\n\nconst props = defineProps({\n title: String,\n borderT: Boolean,\n borderB: Boolean,\n allowOverflow: Boolean,\n titleColor: {\n type: String as () => TitleColor,\n default: 'default'\n },\n button: Object as () =>\n | {\n expandContent?: boolean\n text: string\n to?: string\n color: FormButtonColor\n iconRight?: PropAnyComponent | undefined\n onClick?: () => void\n }\n | undefined,\n alwaysOpen: Boolean,\n lazyLoad: {\n type: Boolean,\n default: false\n }\n})\n\nconst content: Ref<HTMLElement | null> = ref(null)\nconst contentHeight = ref(0)\nconst isExpanded = ref(false)\n\nconst backgroundClass = computed(() => {\n const classes = []\n\n if (!props.button && !props.alwaysOpen) {\n classes.push('cursor-pointer', 'hover:bg-foundation')\n }\n\n if (isExpanded.value) {\n classes.push('bg-foundation')\n }\n\n return classes\n})\n\nconst titleClasses = computed(() => {\n switch (props.titleColor) {\n case 'danger':\n return 'text-danger'\n case 'warning':\n return 'text-warning'\n case 'success':\n return 'text-success'\n case 'secondary':\n return 'text-secondary'\n case 'info':\n return 'text-info'\n default:\n return 'text-foreground'\n }\n})\n\nconst toggleExpansion = async () => {\n isExpanded.value = !isExpanded.value\n\n if (isExpanded.value) {\n await nextTick()\n contentHeight.value = (unref(content)?.scrollHeight || 0) + 64\n }\n}\n</script>\n","<template>\n <div>\n <Disclosure v-slot=\"{ open }\">\n <DisclosureButton :class=\"buttonClasses\">\n <div class=\"inline-flex items-center space-x-2\">\n <Component :is=\"icon\" v-if=\"icon\" class=\"h-5 w-5\" />\n <span>{{ title }}</span>\n </div>\n <ChevronUpIcon :class=\"!open ? 'rotate-180 transform' : ''\" class=\"h-5 w-5\" />\n </DisclosureButton>\n <DisclosurePanel :class=\"panelClasses\">\n <div class=\"label-light\">\n <slot>Panel contents</slot>\n </div>\n </DisclosurePanel>\n </Disclosure>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { DisclosureButton, Disclosure, DisclosurePanel } from '@headlessui/vue'\nimport { ChevronUpIcon } from '@heroicons/vue/24/solid'\nimport { computed } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype DisclosureColor = 'default' | 'danger' | 'success' | 'warning'\n\nconst props = defineProps({\n title: null,\n icon: null,\n color: { default: 'default' }\n})\n\nconst buttonClasses = computed(() => {\n const classParts = [\n 'pr-3 h-10 w-full flex items-center justify-between border-l-2 px-2 rounded transition',\n 'ring-1 font-medium'\n ]\n\n switch (props.color) {\n case 'warning':\n classParts.push(\n 'border-warning text-warning ring-warning-lighter hover:ring-warning'\n )\n break\n case 'success':\n classParts.push(\n 'border-success text-success ring-success-lighter hover:ring-success'\n )\n break\n case 'danger':\n classParts.push('border-danger text-danger ring-danger-lighter hover:ring-danger')\n break\n case 'default':\n default:\n classParts.push(\n 'border-primary text-primary ring-primary-muted hover:ring-primary'\n )\n break\n }\n\n return classParts.join(' ')\n})\n\nconst panelClasses = computed(() => {\n const classParts = ['p-3 border-x border-b rounded-b-md']\n\n switch (props.color) {\n case 'warning':\n classParts.push('border-warning-lighter')\n break\n case 'success':\n classParts.push('border-success-lighter')\n break\n case 'danger':\n classParts.push('border-danger-lighter')\n break\n case 'default':\n default:\n classParts.push('border-primary-muted')\n break\n }\n\n return classParts.join(' ')\n})\n</script>\n","import type { ConcreteComponent } from 'vue'\n\nexport enum GridListToggleValue {\n Grid = 'grid',\n List = 'list'\n}\n\nexport type LayoutTabItem<I extends string = string> = {\n title: string\n id: I\n}\n\nexport type LayoutPageTabItem<I extends string = string> = {\n title: string\n id: I\n icon: ConcreteComponent\n count?: number\n tag?: string\n}\n\nexport type LayoutMenuItem<I extends string = string> = {\n icon?: ConcreteComponent\n title: string\n id: I\n disabled?: boolean\n disabledTooltip?: string\n color?: 'danger' | 'info'\n}\n","<template>\n <button\n class=\"max-w-max transition flex justify-center items-center gap-2 outline-none select-none h-8 text-foreground border-2 border-primary-muted dark:border-foundation bg-primary-muted rounded-md active:scale-[0.97] grow\"\n @click=\"onClick\"\n >\n <div class=\"relative flex bg-primary-muted rounded-md\">\n <div\n class=\"absolute transition\"\n :class=\"{\n 'translate-x-7': value !== GridListToggleValue.Grid\n }\"\n >\n <div\n class=\"w-7 h-7 bg-foundation dark:bg-foundation-2 transition rounded shadow\"\n />\n </div>\n <div\n v-tippy=\"'Grid View'\"\n class=\"relative z-10 flex gap-1 items-center p-1 rounded-l\"\n >\n <Squares2X2Icon class=\"h-5 w-5\" />\n </div>\n <div\n v-tippy=\"'List View'\"\n class=\"relative z-10 flex gap-1 items-center p-1 rounded-r\"\n >\n <Bars3Icon class=\"h-5 w-5\" />\n </div>\n </div>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { Bars3Icon, Squares2X2Icon } from '@heroicons/vue/24/solid'\nimport { computed } from 'vue'\nimport { GridListToggleValue } from '~~/src/helpers/layout/components'\n\nconst emit = defineEmits([\"click\", \"update:modelValue\"])\n\nconst props = defineProps({\n modelValue: null\n})\n\nconst value = computed({\n get: () => props.modelValue || GridListToggleValue.Grid,\n set: (newVal) => emit('update:modelValue', newVal)\n})\n\nconst onClick = (e: MouseEvent) => {\n emit('click', e)\n\n const newVal =\n value.value === GridListToggleValue.Grid\n ? GridListToggleValue.List\n : GridListToggleValue.Grid\n value.value = newVal\n}\n</script>\n","import type { Nullable } from '@speckle/shared'\nimport { isClient } from '@vueuse/core'\nimport type { MaybeRef } from '@vueuse/core'\nimport { debounce, isUndefined, throttle } from 'lodash'\nimport { computed, onBeforeUnmount, onMounted, ref, unref, watch } from 'vue'\n\nexport enum ThrottleOrDebounce {\n Throttle,\n Debounce\n}\n\nexport enum HorizontalDirection {\n Left,\n Right\n}\n\nexport function useWindowResizeHandler(\n handler: (e: UIEvent) => void,\n options?: Partial<{\n wait: number\n throttleOrDebounce: ThrottleOrDebounce\n }>\n) {\n if (!isClient) return\n\n const { wait = 100, throttleOrDebounce = ThrottleOrDebounce.Throttle } = options || {}\n const finalHandler = wait\n ? throttleOrDebounce === ThrottleOrDebounce.Throttle\n ? throttle(handler, wait)\n : debounce(handler, wait)\n : handler\n\n onMounted(() => window.addEventListener('resize', finalHandler))\n onBeforeUnmount(() => window.removeEventListener('resize', finalHandler))\n}\n\nexport function useOnBeforeWindowUnload(handler: (e: BeforeUnloadEvent) => void) {\n onMounted(() => {\n window.addEventListener('beforeunload', handler)\n })\n\n onBeforeUnmount(() => {\n window.removeEventListener('beforeunload', handler)\n })\n}\n\nexport function useResponsiveHorizontalDirectionCalculation(params: {\n el: MaybeRef<Nullable<HTMLElement>>\n defaultDirection?: HorizontalDirection\n /**\n * Stop recalculation below this screen size. Defaults to el.width * 2\n */\n stopUpdatesBelowWidth?: MaybeRef<number>\n}) {\n const { el, defaultDirection } = params\n\n const direction = ref<HorizontalDirection>(\n !isUndefined(defaultDirection) ? defaultDirection : HorizontalDirection.Right\n )\n const stopUpdatesBelowWidth = computed(() => {\n const stopUpdatesBelowWidth = unref(params.stopUpdatesBelowWidth)\n if (!isUndefined(stopUpdatesBelowWidth)) return stopUpdatesBelowWidth\n\n const element = unref(el)\n return element?.offsetWidth ? element.offsetWidth * 2 : undefined\n })\n\n const recalculateDirection = () => {\n if (!isClient) return\n\n const element = unref(el)\n if (!element) return\n\n const rect = element.getBoundingClientRect()\n const showOnLeftSide = rect.x + rect.width > window.innerWidth\n const showOnRightSide = rect.x < 0\n\n // Screen too small - do nothing\n if (\n (showOnLeftSide && showOnRightSide) ||\n (!isUndefined(stopUpdatesBelowWidth.value) &&\n window.innerWidth < stopUpdatesBelowWidth.value)\n )\n return\n\n if (showOnLeftSide) {\n direction.value = HorizontalDirection.Left\n } else if (showOnRightSide) {\n direction.value = HorizontalDirection.Right\n }\n }\n\n useWindowResizeHandler(() => recalculateDirection())\n\n watch(\n () => unref(el),\n (element) => {\n if (element) {\n recalculateDirection()\n }\n }\n )\n\n return {\n direction: computed(() => direction.value),\n recalculateDirection\n }\n}\n","<template>\n <Menu v-slot=\"{ open: isMenuOpen }\" as=\"div\" class=\"relative inline-block\">\n <div>\n <MenuButton ref=\"menuButton\" class=\"hidden\" @click.stop.prevent />\n <!-- conditional pointer-events-none is necessary to avoid double events when clicking on the button when the menu is already open -->\n <div :class=\"isMenuOpen ? 'pointer-events-none' : ''\">\n <slot :toggle=\"toggle\" :open=\"processOpen(isMenuOpen)\" />\n </div>\n </div>\n <Transition\n enter-active-class=\"transition duration-100 ease-out\"\n enter-from-class=\"transform scale-95 opacity-0\"\n enter-to-class=\"transform scale-100 opacity-100\"\n leave-active-class=\"transition duration-75 ease-in\"\n leave-from-class=\"transform scale-100 opacity-100\"\n leave-to-class=\"transform scale-95 opacity-0\"\n >\n <MenuItems\n ref=\"menuItems\"\n :class=\"[\n 'absolute mt-2 w-48 origin-top-right divide-y divide-outline-3 rounded-md bg-foundation shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-40',\n menuDirection === HorizontalDirection.Left ? 'right-0' : ''\n ]\"\n >\n <div v-for=\"(group, i) in items\" :key=\"i\" class=\"p-1\">\n <MenuItem\n v-for=\"item in group\"\n v-slot=\"{ active, disabled }\"\n :key=\"item.id\"\n :disabled=\"item.disabled\"\n :color=\"item.color\"\n >\n <span v-tippy=\"item.disabled && item.disabledTooltip\">\n <button\n :class=\"buildButtonClassses({ active, disabled, color: item.color })\"\n :disabled=\"disabled\"\n @click=\"chooseItem(item, $event)\"\n >\n <Component :is=\"item.icon\" v-if=\"item.icon\" class=\"h-5 w-5\" />\n <slot name=\"item\" :item=\"item\">{{ item.title }}</slot>\n </button>\n </span>\n </MenuItem>\n </div>\n </MenuItems>\n </Transition>\n </Menu>\n</template>\n<script setup lang=\"ts\">\nimport { directive as vTippy } from 'vue-tippy'\nimport { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref, watch } from 'vue'\nimport {\n HorizontalDirection,\n useResponsiveHorizontalDirectionCalculation\n} from '~~/src/composables/common/window'\nimport type { LayoutMenuItem } from '~~/src/helpers/layout/components'\n\nconst emit = defineEmits([\"update:open\", \"chosen\"])\n\nconst props = defineProps({\n open: { type: Boolean },\n items: null\n})\n\nconst menuItems = ref(null as Nullable<{ el: HTMLDivElement }>)\nconst { direction: menuDirection } = useResponsiveHorizontalDirectionCalculation({\n el: computed(() => menuItems.value?.el || null),\n defaultDirection: HorizontalDirection.Left,\n stopUpdatesBelowWidth: 300\n})\n\nconst menuButton = ref(null as Nullable<{ el: HTMLButtonElement }>)\nconst isOpenInternally = ref(false)\n\nconst finalOpen = computed({\n get: () => props.open || false,\n set: (newVal) => emit('update:open', newVal)\n})\n\nconst buildButtonClassses = (params: {\n active?: boolean\n disabled?: boolean\n color?: 'danger' | 'info'\n}) => {\n const { active, disabled, color } = params\n const classParts = [\n 'group flex gap-3 w-full items-center rounded-md px-2 py-1.5 text-sm'\n ]\n\n if (active && !color) {\n classParts.push('bg-foundation-focus text-foreground')\n } else if (disabled) {\n classParts.push('text-foreground-disabled')\n } else if (color === 'danger' && active) {\n classParts.push('text-foreground-on-primary bg-danger')\n } else if (color === 'danger' && !active) {\n classParts.push('text-danger')\n } else if (color === 'info' && active) {\n classParts.push('text-foreground-on-primary bg-info')\n } else if (color === 'info' && !active) {\n classParts.push('text-info')\n } else {\n classParts.push('text-foreground')\n }\n\n return classParts.join(' ')\n}\n\nconst chooseItem = (item: LayoutMenuItem, event: MouseEvent) => {\n emit('chosen', { item, event })\n}\n\nconst toggle = () => menuButton.value?.el.click()\n\n// ok this is a bit hacky, but it's done because of headlessui's limited API\n// the point of this is 1) cast any to bool 2) store 'open' state locally\n// so that we can access it outside of the template\nconst processOpen = (val: unknown): val is boolean => {\n const isOpen = !!val\n isOpenInternally.value = isOpen\n return isOpen\n}\n\nwatch(isOpenInternally, (newVal, oldVal) => {\n if (newVal === oldVal) return\n finalOpen.value = newVal\n})\n\nwatch(finalOpen, (shouldBeOpen) => {\n if (shouldBeOpen && !isOpenInternally.value) {\n toggle()\n } else if (!shouldBeOpen && isOpenInternally.value) {\n toggle()\n }\n})\n</script>\n","<template>\n <div class=\"flex flex-col gap-y-0 sm:gap-y-4\">\n <div class=\"flex gap-x-6\">\n <FormButton\n v-for=\"item in items\"\n :key=\"item.id\"\n link\n :color=\"activeItem.id === item.id ? 'default' : 'secondary'\"\n @click=\"onTabClick(item)\"\n >\n {{ item.title }}\n </FormButton>\n </div>\n <slot :active-item=\"activeItem\" />\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref } from 'vue'\nimport type { LayoutTabItem } from '~~/src/helpers/layout/components'\nimport FormButton from '~~/src/components/form/Button.vue'\n\nconst props = defineProps({\n items: null\n})\n\nconst activeItemId = ref(null as Nullable<string>)\nconst activeItem = computed(() => {\n if (!activeItemId.value) return props.items[0]\n return props.items.find((i) => i.id === activeItemId.value) || props.items[0]\n})\n\nconst onTabClick = (item: LayoutTabItem) => {\n activeItemId.value = item.id\n}\n</script>\n","<template>\n <div\n class=\"relative z-10 flex gap-4\"\n :class=\"vertical ? 'sm:gap-8 flex-col sm:flex-row' : 'sm:gap-10 flex-col'\"\n >\n <div\n class=\"relative flex sm:justify-between overflow-x-auto\"\n :class=\"\n vertical\n ? 'items-center sm:items-start sm:flex-col sm:w-2/12 border-r border-outline gap-4 pl-4'\n : 'border-b border-outline-3 lg:border-none gap-8 w-full'\n \"\n >\n <template v-if=\"!vertical\">\n <div\n class=\"hidden lg:block absolute bottom-0 left-0 h-px w-full bg-outline-3\"\n ></div>\n <div\n :style=\"borderStyle\"\n class=\"h-[2px] absolute bottom-0 z-20 bg-primary transition-all duration-300\"\n ></div>\n </template>\n\n <div\n ref=\"buttonContainer\"\n class=\"flex\"\n :class=\"\n vertical ? 'flex-wrap sm:flex-nowrap flex-row sm:flex-col gap-4' : 'gap-6'\n \"\n >\n <h1\n v-if=\"title\"\n class=\"font-bold h4\"\n :class=\"vertical ? 'w-full sm:w-auto -ml-4 mb-4' : 'mb-2'\"\n >\n {{ title }}\n </h1>\n <button\n v-for=\"item in items\"\n :key=\"item.id\"\n :data-tab-id=\"item.id\"\n class=\"tab-button relative z-10 flex items-center gap-1.5 pb-2 border-b-[2px] border-transparent text-base max-w-max px-2\"\n :class=\"[\n activeItem.id === item.id\n ? 'text-primary hover:text-primary'\n : 'text-foreground',\n vertical ? 'hover:border-outline' : 'hover:border-outline-2'\n ]\"\n @click=\"onTabClick(item)\"\n >\n <Component\n :is=\"item.icon\"\n v-if=\"item.icon\"\n class=\"shrink-0 h-4 w-4 stroke-[2px]\"\n />\n <span class=\"min-w-6\">{{ item.title }}</span>\n <div\n v-if=\"item.count\"\n class=\"rounded-full px-2 text-[11px] transition-all min-w-6\"\n :class=\"\n activeItem.id === item.id\n ? 'text-primary bg-blue-100'\n : 'text-foreground-2 bg-gray-200 dark:bg-foundation'\n \"\n >\n <span>{{ item.count }}</span>\n </div>\n <div\n v-if=\"item.tag\"\n class=\"text-[10px] leading-tight py-0.5 text-foreground-on-primary font-medium px-1.5 rounded-full bg-gradient-to-tr from-[#7025EB] to-primary select-none mt-0.5\"\n >\n {{ item.tag }}\n </div>\n </button>\n </div>\n </div>\n <div :class=\"vertical ? 'sm:w-10/12' : ''\">\n <slot :active-item=\"activeItem\" />\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { computed, ref, watch, type CSSProperties } from 'vue'\nimport type { LayoutPageTabItem } from '~~/src/helpers/layout/components'\nimport { isClient } from '@vueuse/core'\nimport type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'\n\nconst props = defineProps({\n items: null,\n vertical: { type: Boolean },\n title: null\n})\n\nconst buttonContainer = ref(null as Nullable<HTMLDivElement>)\nconst activeItemId = ref<string | null>(null)\n\nconst activeItem = computed(() => {\n const item = props.items.find((i) => i.id === activeItemId.value)\n return item || props.items[0]\n})\n\nconst activeItemRef = computed(() => {\n const id = activeItemId.value\n if (!id) return null\n\n const parent = buttonContainer.value\n if (!parent) return null\n\n const btns = [...parent.getElementsByClassName('tab-button')] as HTMLButtonElement[]\n return btns.find((b) => b.dataset['tabId'] === id) || null\n})\n\nconst borderStyle = computed(() => {\n const element = activeItemRef.value\n const style: CSSProperties = {\n left: `${element?.offsetLeft || 0}px`,\n width: `${element?.clientWidth || 0}px`\n }\n return style\n})\n\nconst onTabClick = (item: LayoutPageTabItem) => {\n activeItemId.value = item.id\n}\n\nconst setActiveItem = (item: MaybeNullOrUndefined<LayoutPageTabItem>) => {\n if (!isClient || !item?.id) return\n\n activeItemId.value = item.id\n}\n\nwatch(\n () => props.items,\n (newItems) => {\n setActiveItem(newItems[0])\n },\n { immediate: true }\n)\n</script>\n","<template>\n <div class=\"text-foreground\">\n <div class=\"w-full text-sm overflow-x-auto overflow-y-visible simple-scrollbar\">\n <div\n v-if=\"items.length > 0\"\n class=\"grid z-10 grid-cols-12 items-center gap-6 font-semibold bg-foundation rounded-t-lg w-full border-b border-outline-3 pb-2 pt-4 px-4 min-w-[900px]\"\n :style=\"{ paddingRight: paddingRightStyle }\"\n >\n <div\n v-for=\"column in columns\"\n :key=\"column.id\"\n :class=\"getHeaderClasses(column.id)\"\n class=\"capitalize\"\n >\n {{ column.header }}\n </div>\n </div>\n <div\n class=\"divide-y divide-outline-3 h-full overflow-visible\"\n :class=\"{ 'pb-32': overflowCells }\"\n >\n <div\n v-for=\"item in items\"\n :key=\"item.id\"\n :style=\"{ paddingRight: paddingRightStyle }\"\n :class=\"rowsWrapperClasses\"\n tabindex=\"0\"\n @click=\"handleRowClick(item)\"\n @keypress=\"handleRowClick(item)\"\n >\n <template v-for=\"(column, colIndex) in columns\" :key=\"column.id\">\n <div :class=\"getClasses(column.id, colIndex)\" tabindex=\"0\">\n <slot :name=\"column.id\" :item=\"item\">\n <div class=\"text-gray-900 font-medium order-1\">Placeholder</div>\n </slot>\n </div>\n </template>\n <div class=\"absolute right-1.5 gap-1 flex items-center p-0 h-full\">\n <div v-for=\"button in buttons\" :key=\"button.label\">\n <FormButton\n :icon-left=\"button.icon\"\n size=\"sm\"\n color=\"secondary\"\n hide-text\n :class=\"button.class\"\n :text-color=\"button.textColor\"\n :to=\"isString(button.action) ? button.action : undefined\"\n @click.stop=\"!isString(button.action) ? button.action(item) : noop\"\n />\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"T extends {id: string}, C extends string\">\nimport { noop, isString } from 'lodash'\nimport { computed } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\nimport type { FormButtonTextColor } from '~~/src/helpers/form/button'\nimport { FormButton } from '~~/src/lib'\n\nexport type TableColumn<I> = {\n id: I\n header: string\n classes: string\n}\n\nexport interface RowButton<T = unknown> {\n icon: PropAnyComponent\n label: string\n action: (item: T) => void | string\n class?: string\n textColor?: FormButtonTextColor\n}\n\nconst props = defineProps({\n items: null,\n buttons: null,\n columns: null,\n overflowCells: { type: Boolean },\n onRowClick: { type: Function },\n rowItemsAlign: { default: 'center' }\n})\n\nconst paddingRightStyle = computed(() => {\n const buttonCount = (props.buttons || []).length\n let padding = 16\n if (buttonCount > 0) {\n padding = 48 + (buttonCount - 1) * 42\n }\n return `${padding}px`\n})\n\nconst rowsWrapperClasses = computed(() => {\n const classParts = [\n 'relative grid grid-cols-12 items-center gap-6 px-4 py-1 min-w-[900px] bg-foundation'\n ]\n\n if (props.onRowClick) {\n classParts.push('cursor-pointer hover:bg-primary-muted')\n }\n\n switch (props.rowItemsAlign) {\n case 'center':\n classParts.push('items-center')\n break\n case 'stretch':\n classParts.push('items-stretch')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst getHeaderClasses = (column: C): string => {\n return props.columns.find((c) => c.id === column)?.classes || ''\n}\n\nconst getClasses = (column: C, colIndex: number): string => {\n const columnClass = getHeaderClasses(column)\n\n if (colIndex === 0) {\n return `bg-transparent py-3 pr-5 px-1 ${columnClass}`\n }\n return `lg:p-0 px-1 my-2 ${columnClass}`\n}\n\nconst handleRowClick = (item: T) => {\n props.onRowClick?.(item)\n}\n</script>\n","<template>\n <div ref=\"wrapper\">\n <InternalInfiniteLoading\n v-if=\"initializeLoader\"\n v-bind=\"$props.settings || {}\"\n @infinite=\"$emit('infinite', $event)\"\n >\n <template #spinner>\n <CommonLoadingBar :loading=\"true\" class=\"my-2\" />\n </template>\n <template #complete>\n <!-- No \"No more items\" message, instead a small amount of spacing -->\n <div class=\"h-8\"></div>\n </template>\n <template #error=\"{ retry }\">\n <div class=\"w-full flex flex-col items-center my-2 space-y-2 mt-4\">\n <div class=\"inline-flex items-center space-x-1\">\n <ExclamationTriangleIcon class=\"w-5 h-5 text-danger\" />\n <span class=\"text-foreground-2\">An error occurred while loading</span>\n </div>\n <FormButton v-if=\"allowRetry\" @click=\"retry\">Retry</FormButton>\n </div>\n </template>\n </InternalInfiniteLoading>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport InternalInfiniteLoading from 'v3-infinite-loading'\nimport { ExclamationTriangleIcon } from '@heroicons/vue/24/outline'\nimport type { InfiniteLoaderState } from '~~/src/helpers/global/components'\nimport type { Nullable } from '@speckle/shared'\nimport CommonLoadingBar from '~~/src/components/common/loading/Bar.vue'\nimport { onMounted, ref } from 'vue'\nimport { isClient } from '@vueuse/core'\nimport FormButton from '~~/src/components/form/Button.vue'\n\ndefineEmits([\"infinite\"])\n\ndefineProps({\n settings: null,\n allowRetry: { type: Boolean }\n})\n\nconst wrapper = ref(null as Nullable<HTMLElement>)\nconst initializeLoader = ref(false)\n\n// This hack is necessary cause sometimes v3-infinite-loading initializes too early and doesnt trigger\nif (isClient) {\n onMounted(() => {\n const int = setInterval(() => {\n if (wrapper.value?.isConnected) {\n initializeLoader.value = true\n clearInterval(int)\n }\n }, 200)\n })\n}\n</script>\n","<template>\n <div class=\"relative group\">\n <div\n v-if=\"fancyGlow\"\n class=\"absolute -inset-1 bg-blue-300 dark:bg-blue-500 opacity-5 dark:opacity-0 rounded-md blur-sm group-hover:opacity-60 dark:group-hover:opacity-30 transition duration-500\"\n ></div>\n <Component\n :is=\"form ? 'form' : 'div'\"\n :class=\"[\n 'relative divide-outline-3 bg-foundation text-foreground flex flex-col divide-y overflow-hidden',\n computedClasses\n ]\"\n @submit=\"emit('submit', $event)\"\n >\n <div v-if=\"$slots.header\" :class=\"secondarySlotPaddingClasses\">\n <slot name=\"header\" />\n </div>\n <div :class=\"['grow', defaultSlotPaddingClasses]\">\n <slot />\n </div>\n <div v-if=\"$slots.footer\" :class=\"secondarySlotPaddingClasses\">\n <slot name=\"footer\" />\n </div>\n </Component>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst emit = defineEmits([\"submit\"])\n\nconst props = defineProps({\n /**\n * Use a `<form/>` element as a wrapper that will emit 'submit' events out from the component when they occur\n */\n form: {\n type: Boolean,\n default: false\n },\n /**\n * Add a ring outline on hover\n */\n ring: {\n type: Boolean,\n default: false\n },\n /**\n * Add a primary-colored glow on hover\n */\n fancyGlow: {\n type: Boolean,\n default: false\n },\n customPadding: {\n type: Boolean,\n default: false\n },\n noShadow: {\n type: Boolean,\n default: false\n },\n panelClasses: {\n type: String\n }\n})\n\nconst secondarySlotPaddingClasses = computed(() =>\n props.customPadding ? '' : 'px-4 py-4 sm:px-6'\n)\nconst defaultSlotPaddingClasses = computed(() =>\n props.customPadding ? '' : 'px-4 py-4 sm:p-6'\n)\n\nconst computedClasses = computed(() => {\n const classParts: string[] = ['rounded-lg']\n\n if (!props.noShadow) classParts.push('shadow')\n if (props.ring) {\n classParts.push('ring-outline-2 hover:ring-2')\n }\n if (props.panelClasses) {\n classParts.push(props.panelClasses)\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <div class=\"rounded-md\" :class=\"[containerClasses, textClasses]\">\n <div class=\"flex\" :class=\"subcontainerClasses\">\n <div class=\"flex-shrink-0\">\n <Component :is=\"icon\" :class=\"iconClasses\" aria-hidden=\"true\" />\n </div>\n <div :class=\"mainContentContainerClasses\">\n <h3 class=\"text-sm\" :class=\"[hasDescription ? 'font-medium' : '']\">\n <slot name=\"title\">Title</slot>\n </h3>\n <div v-if=\"hasDescription\" :class=\"descriptionWrapperClasses\">\n <slot name=\"description\">\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid pariatur,\n ipsum similique veniam.\n </slot>\n </div>\n <div :class=\"actionsContainerClasses\">\n <FormButton\n v-for=\"(action, i) in actions || []\"\n :key=\"i\"\n :color=\"color\"\n :size=\"actionSize\"\n :to=\"action.url\"\n :external=\"action.externalUrl || false\"\n @click=\"action.onClick || noop\"\n >\n {{ action.title }}\n </FormButton>\n </div>\n </div>\n <div\n v-if=\"withDismiss\"\n class=\"flex\"\n :class=\"[hasDescription ? 'items-start' : 'items-center']\"\n >\n <button\n type=\"button\"\n class=\"inline-flex rounded-md focus:outline-none focus:ring-2\"\n :class=\"buttonClasses\"\n @click=\"$emit('dismiss')\"\n >\n <span class=\"sr-only\">Dismiss</span>\n <XMarkIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n CheckCircleIcon,\n XMarkIcon,\n XCircleIcon,\n InformationCircleIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/20/solid'\nimport { noop } from 'lodash'\nimport { computed, useSlots } from 'vue'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype AlertColor = 'success' | 'danger' | 'warning' | 'info'\ntype Size = 'default' | 'xs'\n\ndefineEmits([\"dismiss\"])\n\nconst props = defineProps({\n color: { default: 'success' },\n withDismiss: { type: Boolean },\n actions: null,\n customIcon: null,\n size: { default: 'default' }\n})\n\nconst slots = useSlots()\nconst hasDescription = computed(() => !!slots['description'])\n\nconst icon = computed(() => {\n if (props.customIcon) return props.customIcon\n\n switch (props.color) {\n case 'info':\n return InformationCircleIcon\n case 'warning':\n return ExclamationCircleIcon\n case 'danger':\n return XCircleIcon\n case 'success':\n default:\n return CheckCircleIcon\n }\n})\n\nconst containerClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case 'xs':\n classParts.push('p-1')\n break\n case 'default':\n default:\n classParts.push(hasDescription.value ? 'p-3 sm:p-4' : 'p-2')\n break\n }\n\n switch (props.color) {\n case 'success':\n classParts.push('bg-success-lighter border-l-4 border-success')\n break\n case 'info':\n classParts.push('bg-info-lighter border-l-4 border-info')\n break\n case 'danger':\n classParts.push('bg-danger-lighter border-l-4 border-danger')\n break\n case 'warning':\n classParts.push('bg-warning-lighter border-l-4 border-warning')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst subcontainerClasses = computed(() => {\n const classParts: string[] = []\n\n if (hasDescription.value) {\n classParts.push('')\n } else {\n classParts.push('items-center')\n\n switch (props.size) {\n case 'xs':\n classParts.push('space-x-1')\n break\n case 'default':\n default:\n classParts.push('space-x-2')\n break\n }\n }\n\n return classParts.join(' ')\n})\n\nconst mainContentContainerClasses = computed(() => {\n const classParts: string[] = ['grow']\n\n if (!hasDescription.value) {\n classParts.push('flex items-center space-x-2')\n }\n\n switch (props.size) {\n case 'xs':\n classParts.push('ml-1')\n break\n case 'default':\n default:\n classParts.push('ml-3')\n\n break\n }\n\n return classParts.join(' ')\n})\n\nconst descriptionWrapperClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case 'xs':\n classParts.push('text-xs')\n break\n case 'default':\n default:\n classParts.push('mt-1 sm:mt-2 text-xs sm:text-sm')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst actionsContainerClasses = computed(() => {\n const classParts: string[] = ['flex']\n\n if (!hasDescription.value) {\n classParts.push('grow justify-end')\n }\n\n const hasDescriptionAndActions = hasDescription.value && props.actions?.length\n\n switch (props.size) {\n case 'xs':\n classParts.push('space-x-1')\n if (hasDescriptionAndActions) {\n classParts.push('mt-1')\n }\n break\n case 'default':\n default:\n classParts.push('space-x-2')\n if (hasDescriptionAndActions) {\n classParts.push('mt-4')\n }\n break\n }\n\n return classParts.join(' ')\n})\n\nconst textClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.color) {\n case 'success':\n classParts.push('text-success-darker')\n break\n case 'info':\n classParts.push('text-info-darker')\n break\n case 'danger':\n classParts.push('text-danger-darker')\n break\n case 'warning':\n classParts.push('text-warning-darker')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case 'xs':\n classParts.push('h-4 w-4')\n classParts.push(hasDescription.value ? 'mt-0.5' : '')\n break\n case 'default':\n default:\n classParts.push('h-5 w-5')\n break\n }\n\n switch (props.color) {\n case 'success':\n classParts.push('text-success')\n break\n case 'info':\n classParts.push('text-info')\n break\n case 'danger':\n classParts.push('text-danger')\n break\n case 'warning':\n classParts.push('text-warning')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst buttonClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.color) {\n case 'success':\n classParts.push('bg-success-lighter ring-success')\n break\n case 'info':\n classParts.push('bg-info-lighter ring-info')\n break\n case 'danger':\n classParts.push('bg-danger-lighter ring-danger')\n break\n case 'warning':\n classParts.push('bg-warning-lighter ring-warning')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst actionSize = computed(() => {\n switch (props.size) {\n case 'xs':\n return 'xs'\n case 'default':\n default:\n return 'sm'\n }\n})\n</script>\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { MaybeAsync } from '@speckle/shared'\nimport { computedAsync } from '@vueuse/core'\nimport type { AsyncComputedOptions } from '@vueuse/core'\nimport { computed } from 'vue'\nimport type { ComputedRef } from 'vue'\n\nexport interface AsyncWritableComputedOptions<T> {\n get: (...args: any[]) => MaybeAsync<T>\n set: (value: T) => MaybeAsync<void>\n initialState: T\n readOptions?: AsyncComputedOptions\n asyncRead?: boolean\n debugging?: Partial<{\n log: {\n name: string\n writesOnly?: boolean\n readsOnly?: boolean\n logger?: (msg: string, ...args: any[]) => void\n }\n }>\n}\n\nexport type AsyncWritableComputedRef<T> = ComputedRef<T> & {\n update: AsyncWritableComputedOptions<T>['set']\n}\n\n/**\n * Allows async read/write from/to computed. Use `res.value` to read and `res.update` to write. If you only need\n * the computed to be read-only then use vueuse's `computedAsync`. If you only need async writes you can\n * disable async reads through the `asyncRead` param.\n * @param params\n */\nexport function writableAsyncComputed<T>(\n params: AsyncWritableComputedOptions<T>\n): AsyncWritableComputedRef<T> {\n const { get, initialState, readOptions, set, asyncRead = true, debugging } = params\n const logSettings = debugging?.log\n const getTrace = () => (new Error('Trace:').stack || '').substring(7)\n const logger = params.debugging?.log?.logger || console.debug\n\n const finalGet: typeof get =\n logSettings && !logSettings.writesOnly\n ? () => {\n const res = get()\n logger(`debugging: '${logSettings.name}' read`, res, getTrace())\n return res\n }\n : get\n\n const finalSet: typeof set =\n logSettings && !logSettings.readsOnly\n ? (newVal) => {\n logger(`debugging: '${logSettings.name}' written to`, newVal, getTrace())\n return set(newVal)\n }\n : set\n\n const readValue = asyncRead\n ? computedAsync(finalGet, initialState, readOptions)\n : computed(finalGet)\n\n const getter = computed(() => readValue.value) as AsyncWritableComputedRef<T>\n getter.update = finalSet\n\n return getter\n}\n\n/**\n * Build promise that can be resolved/rejected manually outside of the promise's execution scope\n */\nexport const buildManualPromise = <T>() => {\n let resolve: (value: T) => void\n let reject: (reason?: any) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n\n const resolveWrapper: typeof resolve = (...args) => resolve(...args)\n const rejectWrapper: typeof reject = (...args) => reject(...args)\n\n return { promise, resolve: resolveWrapper, reject: rejectWrapper }\n}\n","<script lang=\"ts\">\nenum Focus {\n /** Focus the first non-disabled item. */\n First,\n\n /** Focus the previous non-disabled item. */\n Previous,\n\n /** Focus the next non-disabled item. */\n Next,\n\n /** Focus the last non-disabled item. */\n Last,\n\n /** Focus a specific item based on the `id` of the item. */\n Specific,\n\n /** Focus no items at all. */\n Nothing\n}\nenum ComboboxStates {\n Open,\n Closed\n}\n</script>\n<template>\n <slot />\n</template>\n<script setup lang=\"ts\">\nimport type { Nullable, Optional } from '@speckle/shared'\nimport { getCurrentInstance, inject } from 'vue'\nimport type { ComponentInternalInstance, Ref } from 'vue'\n\n/**\n * Sort of hacky - we need to manipulate the @headlessui combobox state, but it can't be injected\n * from its parent component (Tags.vue). This being initialized inside of a slot of the combobox,\n * it has access to the context\n *\n * Also the context is inaccessible due to it being tied to a private symbol, so we need\n * to retrieve that a bit hackily too.\n */\n\n// Copied from headlessui\n\n\n\n\nconst instance = getCurrentInstance() as ComponentInternalInstance & {\n provides: Record<symbol | string, unknown>\n}\nconst provides = instance['provides']\nconst ctxKey = Object.getOwnPropertySymbols(provides).find(\n (s) => s.description === 'ComboboxContext'\n)\nif (!ctxKey) {\n console.error('FormTagsContextManager ctx key not found!')\n}\n\nconst state = inject(ctxKey || '__undefined') as Optional<{\n goToOption: (focus: Focus) => void\n openCombobox: () => void\n closeCombobox: () => void\n activeOptionIndex: Ref<Nullable<number>>\n selectActiveOption: () => void\n comboboxState: Ref<ComboboxStates>\n}>\n\nif (!state) {\n console.error('FormTagsContextManager ctx not found!')\n}\n\nconst goUp = () => {\n state?.goToOption(Focus.Previous)\n}\nconst goDown = () => {\n state?.goToOption(Focus.Next)\n}\nconst open = () => {\n if (!state) return\n state.openCombobox()\n}\nconst close = () => {\n state?.closeCombobox()\n}\nconst selectActive = () => {\n state?.selectActiveOption()\n}\nconst isOpen = () => state?.comboboxState.value === ComboboxStates.Open\n\ndefineExpose({ goUp, goDown, open, close, selectActive, isOpen })\n</script>\n","<template>\n <Combobox\n v-model=\"selectedItems\"\n as=\"div\"\n multiple\n clearable\n :class=\"[wrapperClasses]\"\n >\n <FormTagsContextManager ref=\"ctxManager\">\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n <div\n class=\"relative flex flex-wrap items-center space-x-1 px-2 py-1\"\n :class=\"inputWrapperClasses\"\n >\n <CommonBadge\n v-for=\"tag in selectedItems\"\n :key=\"tag\"\n :icon-left=\"!disabled ? XMarkIcon : undefined\"\n clickable-icon\n size=\"lg\"\n @click-icon=\"() => removeTag(tag)\"\n >\n {{ tag }}\n </CommonBadge>\n <input\n ref=\"inputEl\"\n v-model=\"query\"\n :disabled=\"disabled\"\n class=\"bg-transparent grow shrink border-0 focus:ring-0 p-0\"\n :class=\"[coreInputClasses, sizeClasses]\"\n style=\"flex-basis: 70px; min-width: 70px\"\n :placeholder=\"!selectedItems.length ? placeholder : undefined\"\n @input=\"onQueryInput\"\n @keydown.escape=\"onQueryEscape\"\n @keydown.enter.stop.prevent=\"onQueryInput($event, true)\"\n @keydown.tab=\"onQueryInput\"\n @keydown.backspace=\"onQueryBackspace\"\n @keydown.arrow-up=\"onQueryArrowUp\"\n @keydown.arrow-down=\"onQueryArrowDown\"\n @blur=\"isAutocompleteOpen = false\"\n />\n <a\n v-if=\"shouldShowClear\"\n title=\"Clear input\"\n class=\"absolute top-2 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-if=\"errorMessage\"\n :class=\"[\n 'pointer-events-none absolute top-[10px] right-0 flex items-center',\n shouldShowClear ? 'pr-8' : 'pr-2'\n ]\"\n >\n <ExclamationCircleIcon class=\"h-4 w-4 text-danger\" aria-hidden=\"true\" />\n </div>\n <div\n v-if=\"showRequired && !errorMessage\"\n class=\"pointer-events-none absolute top-[2px] text-4xl right-0 flex items-center text-danger opacity-50\"\n :class=\"shouldShowClear ? 'pr-8' : 'pr-2'\"\n >\n *\n </div>\n </div>\n <TransitionRoot\n leave=\"transition ease-in duration-100\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n class=\"relative px-0.5\"\n >\n <ComboboxOptions\n class=\"absolute top-1 max-h-60 w-full overflow-auto simple-scrollbar rounded-md bg-foundation-2 py-1 shadow label label--light outline outline-2 outline-primary-muted focus:outline-none\"\n >\n <div\n v-if=\"isAutocompleteLoading\"\n class=\"px-1\"\n :class=\"autocompleteItems.length ? 'mb-1' : ''\"\n >\n <CommonLoadingBar :loading=\"true\" />\n </div>\n <div v-if=\"!autocompleteItems.length && !isAutocompleteLoading\">\n <div class=\"text-foreground-2 text-center\">\n Press\n <strong>Enter</strong>\n to create tag ⚡\n </div>\n </div>\n <template v-if=\"autocompleteItems.length\">\n <ComboboxOption\n v-for=\"tag in autocompleteItems\"\n :key=\"tag\"\n v-slot=\"{ selected, active }\"\n as=\"template\"\n :value=\"tag\"\n >\n <li\n class=\"relative cursor-pointer select-none py-1.5 pl-3\"\n :class=\"{\n 'text-primary': active,\n 'text-foreground': !active\n }\"\n >\n <span\n class=\"block truncate\"\n :class=\"{ 'font-medium': selected, 'font-normal': !selected }\"\n >\n {{ tag }}\n </span>\n <span\n v-if=\"selected\"\n class=\"absolute inset-y-0 right-0 flex items-center pr-4\"\n :class=\"{ 'text-primary': active, 'text-foreground': !active }\"\n >\n <CheckIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </span>\n </li>\n </ComboboxOption>\n </template>\n </ComboboxOptions>\n </TransitionRoot>\n <p v-if=\"helpTipId && !hideHelpTip\" :id=\"helpTipId\" :class=\"helpTipClasses\">\n {{ helpTip }}\n </p>\n </FormTagsContextManager>\n </Combobox>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, toRefs, watch, onMounted } from 'vue'\nimport {\n Combobox,\n ComboboxOptions,\n ComboboxOption,\n TransitionRoot\n} from '@headlessui/vue'\nimport { CheckIcon, XMarkIcon, ExclamationCircleIcon } from '@heroicons/vue/20/solid'\nimport { debounce, uniq } from 'lodash'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport type { RuleExpression } from 'vee-validate'\nimport type { MaybeAsync, Nullable } from '@speckle/shared'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\nimport FormTagsContextManager from '~~/src/components/form/tags/ContextManager.vue'\nimport { useFocus } from '@vueuse/core'\nimport CommonLoadingBar from '~~/src/components/common/loading/Bar.vue'\n\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\ntype Tag = string\nconst isInputEvent = (e: Event): e is InputEvent => e.type === 'input'\n\nconst emit = defineEmits([\"update:modelValue\", \"change\", \"clear\"])\n\nconst props = defineProps({\n name: null,\n help: null,\n label: null,\n showLabel: { type: Boolean },\n rules: null,\n validateOnMount: { type: Boolean },\n validateOnValueUpdate: { type: Boolean },\n autoFocus: { type: Boolean },\n showClear: { type: Boolean },\n showRequired: { type: Boolean },\n color: { default: 'page' },\n wrapperClasses: null,\n size: { default: 'base' },\n placeholder: null,\n disabled: { type: Boolean },\n useLabelInErrors: { type: Boolean, default: true },\n getAutocompleteItems: { type: Function },\n modelValue: null\n})\n\n// const localValue = defineModel<Tag[]>({ local: true })\nconst inputEl = ref(null as Nullable<HTMLInputElement>)\nconst { focused: isInputFocused } = useFocus(inputEl)\n\nconst ctxManager = ref(\n null as Nullable<{\n goUp: () => void\n goDown: () => void\n open: () => void\n close: () => void\n selectActive: () => void\n isOpen: () => boolean\n }>\n)\n\nconst {\n coreInputClasses,\n coreClasses,\n labelClasses,\n title,\n helpTip,\n helpTipId,\n hideHelpTip,\n helpTipClasses,\n errorMessage,\n clear,\n value\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl\n // options: {\n // customClear: () => (selectedItems.value = [])\n // }\n})\n\nconst autocompleteItems = ref([] as string[])\nconst isAutocompleteLoading = ref(false)\nconst isAutocompleteOpen = ref(false)\nconst query = ref('')\n\nconst selectedItems = computed({\n get: () => value.value || [],\n set: (newVal) => {\n value.value = uniq(newVal).filter((t) => !!t.length)\n }\n})\n\nconst sizeClasses = computed((): string => {\n switch (props.size) {\n case 'sm':\n return 'h-6'\n case 'lg':\n return 'h-10'\n case 'xl':\n return 'h-14'\n case 'base':\n default:\n return 'h-8'\n }\n})\n\nconst shouldShowClear = computed(() => props.showClear && !!selectedItems.value.length)\n\nconst inputWrapperClasses = computed(() => {\n const classParts: string[] = [\n coreClasses.value,\n props.disabled\n ? 'cursor-not-allowed !bg-foundation-disabled !text-disabled-muted'\n : ''\n ]\n\n if (shouldShowClear.value && (errorMessage.value || props.showRequired)) {\n classParts.push('pr-14')\n } else if (shouldShowClear.value || errorMessage.value || props.showRequired) {\n classParts.push('pr-8')\n }\n\n if (errorMessage.value) {\n classParts.push('border-2 border-danger text-danger-darker')\n if (isInputFocused.value) {\n classParts.push('ring-1 ring-danger')\n }\n } else {\n classParts.push('border-2 border-transparent')\n if (isInputFocused.value) {\n classParts.push('ring-2 ring-outline-2')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst removeTag = (tag: Tag) => {\n if (props.disabled) return\n\n const idx = selectedItems.value.indexOf(tag)\n if (idx !== -1) {\n const newSelected = selectedItems.value.slice()\n newSelected.splice(idx, 1)\n\n selectedItems.value = newSelected\n }\n}\n\nconst onQueryEscape = () => {\n inputEl.value?.blur()\n isAutocompleteOpen.value = false\n}\n\nconst onQueryBackspace = (e: KeyboardEvent) => {\n if (e.key !== 'Backspace') return\n if (query.value.length) return\n\n // Clear last tag\n const newTags = selectedItems.value.slice()\n newTags.pop()\n selectedItems.value = newTags\n isAutocompleteOpen.value = false\n}\n\nconst onQueryArrowUp = () => {\n if (ctxManager.value?.isOpen()) {\n ctxManager.value?.goUp()\n } else {\n ctxManager.value?.open()\n }\n}\n\nconst onQueryArrowDown = () => {\n if (ctxManager.value?.isOpen()) {\n ctxManager.value?.goDown()\n } else {\n ctxManager.value?.open()\n }\n}\n\nconst resolveAutocompleteItems = async () => {\n if (!props.getAutocompleteItems) return\n\n isAutocompleteLoading.value = true\n autocompleteItems.value = await Promise.resolve(\n props.getAutocompleteItems(query.value)\n )\n isAutocompleteLoading.value = false\n}\nconst debouncedResolve = debounce(resolveAutocompleteItems, 1000)\nconst debouncedResolveAndMarkLoading = () => {\n isAutocompleteLoading.value = true\n debouncedResolve()\n}\n\nconst onQueryInput = (e: Event, forceCreateFromInput?: boolean) => {\n const isAddingTag = isInputEvent(e)\n ? e.data === ' ' || e.data === ',' || e.data === ';'\n : true\n\n if (isAddingTag) {\n let selected = false\n if (\n ctxManager.value?.isOpen() &&\n autocompleteItems.value.length &&\n !forceCreateFromInput\n ) {\n // Add from opened autocomplete panel\n ctxManager.value?.selectActive()\n selected = true\n } else {\n // Add from query\n const newTag = query.value\n .trim()\n .substring(0, query.value.length - (isInputEvent(e) ? 1 : 0))\n\n const tagExists = selectedItems.value.includes(newTag)\n if (newTag.length > 0 && !tagExists) {\n selectedItems.value = [...selectedItems.value, newTag]\n selected = true\n }\n }\n\n if (selected) {\n query.value = ''\n isAutocompleteOpen.value = false\n }\n } else {\n isAutocompleteOpen.value = !!query.value.length\n }\n}\n\nwatch(isAutocompleteOpen, (newIsOpen, oldIsOpen) => {\n if (newIsOpen && !oldIsOpen) {\n if (props.getAutocompleteItems) ctxManager.value?.open()\n } else if (!newIsOpen && oldIsOpen) {\n ctxManager.value?.close()\n }\n})\n\nwatch(query, () => {\n debouncedResolveAndMarkLoading()\n})\n\n// // syncing value w/ vee-validate internal state\n// watch(\n// selectedItems,\n// (newVal) => {\n// value.value = newVal.slice()\n// },\n// { deep: true, immediate: true }\n// )\n\nonMounted(() => {\n resolveAutocompleteItems()\n})\n\ndefineExpose({ resolveAutocompleteItems })\n</script>\n","import { computed } from 'vue'\nimport type { ToRefs } from 'vue'\n\nexport type AvatarUser = {\n name: string\n avatar?: string | null\n}\n\nexport type AvatarUserWithId = AvatarUser & { id: string }\n\nexport type UserAvatarSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | 'xxl' | 'editable'\n\nexport function useAvatarSizeClasses(params: {\n props: ToRefs<{\n size?: UserAvatarSize\n }>\n}) {\n const { props } = params\n\n const heightClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'h-5'\n case 'sm':\n return 'h-6'\n case 'lg':\n return 'h-10'\n case 'xl':\n return 'h-14'\n case 'xxl':\n return 'h-32'\n case 'editable':\n return 'h-60'\n case 'base':\n default:\n return 'h-8'\n }\n })\n\n const widthClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'w-5'\n case 'sm':\n return 'w-6'\n case 'lg':\n return 'w-10'\n case 'xl':\n return 'w-14'\n case 'xxl':\n return 'w-32'\n case 'editable':\n return 'w-60'\n case 'base':\n default:\n return 'w-8'\n }\n })\n\n const textClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'text-tiny'\n case 'sm':\n return 'text-xs'\n case 'lg':\n return 'text-md'\n case 'xl':\n return 'text-2xl'\n case 'xxl':\n return 'text-3xl'\n case 'editable':\n return 'h1'\n case 'base':\n default:\n return 'text-sm'\n }\n })\n\n const iconClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'w-3 h-3'\n case 'sm':\n return 'w-3 h-3'\n case 'lg':\n return 'w-5 h-5'\n case 'xl':\n return 'w-8 h-8'\n case 'xxl':\n return 'w-10 h-10'\n case 'editable':\n return 'w-20 h-20'\n case 'base':\n default:\n return 'w-4 h-4'\n }\n })\n\n const sizeClasses = computed(\n () => `${widthClasses.value} ${heightClasses.value} ${textClasses.value}`\n )\n\n return { heightClasses, widthClasses, sizeClasses, iconClasses }\n}\n","<template>\n <div\n :class=\"[\n 'text-foreground-on-primary flex shrink-0 items-center justify-center overflow-hidden rounded-full font-semibold uppercase transition',\n sizeClasses,\n bgClasses,\n borderClasses,\n hoverClasses,\n activeClasses\n ]\"\n >\n <slot>\n <div\n v-if=\"user?.avatar\"\n class=\"h-full w-full bg-cover bg-center bg-no-repeat\"\n :style=\"{ backgroundImage: `url('${user.avatar}')` }\"\n />\n <div\n v-else-if=\"initials\"\n class=\"flex h-full w-full select-none items-center justify-center\"\n >\n {{ initials }}\n </div>\n <div v-else><UserCircleIcon :class=\"iconClasses\" /></div>\n </slot>\n <slot name=\"absolute-anchor\" />\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { UserCircleIcon } from '@heroicons/vue/24/solid'\nimport type { MaybeNullOrUndefined } from '@speckle/shared'\nimport { computed, toRefs } from 'vue'\nimport { useAvatarSizeClasses } from '~~/src/composables/user/avatar'\nimport type { AvatarUser, UserAvatarSize } from '~~/src/composables/user/avatar'\n\nconst props = defineProps({\n user: { default: null },\n size: { default: 'base' },\n hoverEffect: { type: Boolean, default: false },\n active: { type: Boolean },\n noBorder: { type: Boolean },\n noBg: { type: Boolean }\n})\n\nconst { sizeClasses, iconClasses } = useAvatarSizeClasses({ props: toRefs(props) })\n\nconst initials = computed(() => {\n if (!props.user?.name.length) return\n const parts = props.user.name.split(' ')\n const firstLetter = parts[0]?.[0] || ''\n const secondLetter = parts[1]?.[0] || ''\n\n if (props.size === 'sm' || props.size === 'xs') return firstLetter\n return firstLetter + secondLetter\n})\n\nconst borderClasses = computed(() => {\n if (props.noBorder) return ''\n return 'border-2 border-foundation'\n})\n\nconst bgClasses = computed(() => {\n if (props.noBg) return ''\n return 'bg-primary'\n})\n\nconst hoverClasses = computed(() => {\n if (props.hoverEffect)\n return 'hover:border-primary focus:border-primary active:scale-95'\n return ''\n})\n\nconst activeClasses = computed(() => {\n if (props.active) return 'border-primary'\n return ''\n})\n</script>\n","<template>\n <div ref=\"elementToWatchForChanges\" :class=\"`flex ${overlap ? '-space-x-2' : ''}`\">\n <div\n ref=\"itemContainer\"\n :class=\"`flex flex-wrap overflow-hidden ${\n overlap ? '-space-x-2 ' : ''\n } ${heightClasses}`\"\n >\n <UserAvatar\n v-for=\"(user, i) in items\"\n :key=\"user.id || i\"\n :user=\"user\"\n :size=\"size\"\n />\n </div>\n <UserAvatar v-if=\"finalHiddenItemCount\" :size=\"size\">\n +{{ finalHiddenItemCount }}\n </UserAvatar>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref, toRefs } from 'vue'\nimport UserAvatar from '~~/src/components/user/Avatar.vue'\nimport { useWrappingContainerHiddenCount } from '~~/src/composables/layout/resize'\nimport { useAvatarSizeClasses } from '~~/src/composables/user/avatar'\nimport type { UserAvatarSize, AvatarUserWithId } from '~~/src/composables/user/avatar'\n\nconst props = defineProps({\n users: { default: () => [] },\n overlap: { type: Boolean, default: true },\n size: { default: 'base' },\n maxCount: { default: undefined }\n})\n\nconst elementToWatchForChanges = ref(null as Nullable<HTMLElement>)\nconst itemContainer = ref(null as Nullable<HTMLElement>)\n\nconst { hiddenItemCount } = useWrappingContainerHiddenCount({\n elementToWatchForChanges,\n itemContainer,\n trackResize: true,\n trackMutations: true\n})\n\nconst { heightClasses } = useAvatarSizeClasses({ props: toRefs(props) })\n\nconst maxCountHiddenItemCount = computed(() => {\n if (!props.maxCount) return 0\n return Math.max(props.users.length - props.maxCount, 0)\n})\n\nconst finalHiddenItemCount = computed(\n () => hiddenItemCount.value + maxCountHiddenItemCount.value\n)\n\nconst items = computed(() =>\n props.maxCount ? props.users.slice(0, props.maxCount) : props.users\n)\n</script>\n","<template>\n <ArrowPathIcon :class=\"iconClasses\" />\n</template>\n<script setup lang=\"ts\">\nimport { ArrowPathIcon } from '@heroicons/vue/24/solid'\nimport { computed } from 'vue'\n\ntype Size = 'base' | 'sm' | 'lg'\n\nconst props = defineProps({\n loading: { type: Boolean, default: true },\n size: { default: 'base' }\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['text-primary transition-all animate-spin']\n classParts.push(props.loading ? 'opacity-100' : 'opacity-0')\n\n switch (props.size) {\n case 'base':\n classParts.push('h-8 w-8')\n break\n case 'sm':\n classParts.push('h-5 w-5')\n break\n case 'lg':\n classParts.push('h-12 w-12')\n break\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <div class=\"flex flex-col items-center space-y-2\">\n <LazyUserAvatarEditor\n v-if=\"editMode\"\n :user=\"modelAsUser\"\n :disabled=\"disabled\"\n :size=\"size\"\n @cancel=\"editMode = false\"\n @save=\"onSave\"\n />\n <div v-else class=\"relative group\">\n <UserAvatar :user=\"modelAsUser\" :size=\"size\" />\n <div\n class=\"opacity-0 transition-all absolute group-hover:opacity-100 inset-0 flex items-end justify-center bottom-4\"\n >\n <FormButton :disabled=\"disabled\" color=\"secondary\" @click=\"editMode = true\">\n Change\n </FormButton>\n </div>\n </div>\n <div v-if=\"errorMessage\" class=\"w-full text-center text-danger text-sm\">\n {{ errorMessage }}\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'\nimport { computed, defineAsyncComponent } from 'vue'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport UserAvatar from '~~/src/components/user/Avatar.vue'\nimport type { AvatarUser, UserAvatarSize } from '~~/src/composables/user/avatar'\nimport CommonLoadingIcon from '~~/src/components/common/loading/Icon.vue'\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\n\ntype ModelType = MaybeNullOrUndefined<string>\n\nconst LazyUserAvatarEditor = defineAsyncComponent({\n loader: () => import('~~/src/components/user/AvatarEditor.vue'),\n loadingComponent: CommonLoadingIcon,\n delay: 100\n})\n\nconst emit = defineEmits([\"save\", \"update:modelValue\"])\n\nconst props = defineProps({\n modelValue: null,\n placeholder: null,\n name: null,\n rules: null,\n validateOnMount: { type: Boolean },\n validateOnValueUpdate: { type: Boolean },\n disabled: { type: Boolean },\n size: null\n})\n\nconst { value, errorMessage } = useField<ModelType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n initialValue: props.modelValue || undefined\n})\n\nconst editMode = defineModel<boolean>('editMode', { local: true })\n\nconst modelAsUser = computed(\n (): AvatarUser => ({\n avatar: value.value,\n name: props.placeholder\n })\n)\n\nconst onSave = (newUrl: Nullable<string>) => {\n value.value = newUrl\n emit('save', newUrl)\n}\n\nconst open = () => (editMode.value = true)\nconst close = () => (editMode.value = false)\n\ndefineExpose({ open, close })\n</script>\n","/**\n * Base ObjectLoader error\n */\nexport abstract class BaseError extends Error {\n /**\n * Default message if none is passed\n */\n static defaultMessage = 'Unexpected error occurred'\n\n constructor(message?: string, options?: ErrorOptions) {\n message ||= new.target.defaultMessage\n super(message, options)\n }\n}\n\n/**\n * Throw these in execution branches that should never occur unless if there's a bug\n */\nexport class LogicError extends BaseError {\n static defaultMessage = 'An unexpected logic error occurred!'\n}\n\nexport class UninitializedResourceAccessError extends BaseError {\n static defaultMessage = 'Attempting to access an uninitialized resource'\n}\n\nexport class ComposableInvokedOutOfScopeError extends BaseError {\n static defaultMessage =\n 'getCurrentInstance() returned null. Method must be called at the top of a setup function'\n}\n\n/**\n * Throw this when something that's only supported during CSR is invoked during SSR or vice versa\n */\nexport class UnsupportedEnvironmentError extends BaseError {\n static defaultMessage =\n 'Operation not supported in current (server or client) environment'\n}\n","import { difference, intersection } from 'lodash'\nimport { md5 } from '@speckle/shared'\nimport type { Nullable } from '@speckle/shared'\nimport { BaseError } from '~~/src/helpers/common/error'\n\nexport type FileTypeSpecifier = UniqueFileTypeSpecifier | `.${string}`\n\nexport enum UniqueFileTypeSpecifier {\n AnyAudio = 'audio/*',\n AnyVideo = 'video/*',\n AnyImage = 'image/*'\n}\n\n/**\n * Validate if file has the allowed type. While we could also test for MIME types\n * not in UniqueFileTypeSpecifier, this function is meant to be equivalent to the\n * 'accept' attribute, which only allows for extensions or UniqueFileTypeSpecifier\n * values.\n * @param file\n * @param allowedTypes The file must have one of these types\n * @returns True if valid, Error object if not\n */\nexport function validateFileType(\n file: File,\n allowedTypes: FileTypeSpecifier[]\n): true | Error {\n // Check one of the unique file type specifiers first\n const allowedUniqueTypes = intersection(\n Object.values(UniqueFileTypeSpecifier),\n allowedTypes\n )\n for (const allowedUniqueType of allowedUniqueTypes) {\n switch (allowedUniqueType) {\n case UniqueFileTypeSpecifier.AnyAudio:\n if (file.type.startsWith('audio')) return true\n break\n case UniqueFileTypeSpecifier.AnyImage:\n if (file.type.startsWith('image')) return true\n break\n case UniqueFileTypeSpecifier.AnyVideo:\n if (file.type.startsWith('video')) return true\n break\n }\n }\n\n // Check file extensions\n const allowedExtensions = difference(allowedTypes, allowedUniqueTypes)\n const fileExt = resolveFileExtension(file.name)\n if (!fileExt) return new MissingFileExtensionError()\n\n for (const allowedExtension of allowedExtensions) {\n if (allowedExtension.toLowerCase() === fileExt.toLowerCase()) return true\n }\n\n return new ForbiddenFileTypeError()\n}\n\n/**\n * Resolve file extension (with leading dot)\n */\nexport function resolveFileExtension(fileName: string): Nullable<FileTypeSpecifier> {\n const ext = fileName.split('.').pop() || null\n return ext ? `.${ext}` : null\n}\n\n/**\n * Check if string is a FileTypeSpecifier\n */\nexport function isFileTypeSpecifier(type: string): type is FileTypeSpecifier {\n return (\n type.startsWith('.') ||\n Object.values(UniqueFileTypeSpecifier as Record<string, string>).includes(type)\n )\n}\n\n/**\n * Create a human readable file size string from the numeric size in bytes\n */\nexport function prettyFileSize(sizeInBytes: number): string {\n const removeTrailingZeroes = (fileSize: number) =>\n parseFloat(fileSize.toFixed(2)).toString()\n\n if (sizeInBytes < 1024) {\n return `${sizeInBytes}bytes`\n }\n\n const kbSize = sizeInBytes / 1024\n if (kbSize < 1024) {\n return `${removeTrailingZeroes(kbSize)}KB`\n }\n\n const mbSize = kbSize / 1024\n if (mbSize < 1024) {\n return `${removeTrailingZeroes(mbSize)}MB`\n }\n\n const gbSize = mbSize / 1024\n return `${removeTrailingZeroes(gbSize)}GB`\n}\n\n/**\n * Generate an ID that uniquely identifies a specific file. The same file\n * will always have the same ID.\n */\nexport function generateFileId(file: File): string {\n const importantData = {\n name: file.name,\n lastModified: file.lastModified,\n size: file.size,\n type: file.type\n }\n\n return md5(JSON.stringify(importantData))\n}\n\nexport class MissingFileExtensionError extends BaseError {\n static defaultMessage = 'The selected file has a missing extension'\n}\n\nexport class ForbiddenFileTypeError extends BaseError {\n static defaultMessage = 'The selected file type is forbidden'\n}\n","import type { MaybeRef } from '@vueuse/core'\nimport type { MaybeNullOrUndefined, Nullable, Optional } from '@speckle/shared'\nimport {\n generateFileId,\n isFileTypeSpecifier,\n prettyFileSize,\n validateFileType\n} from '~~/src/helpers/form/file'\nimport type { FileTypeSpecifier } from '~~/src/helpers/form/file'\nimport { computed, unref } from 'vue'\nimport type { CSSProperties } from 'vue'\nimport { BaseError } from '~~/src/lib'\n\n/**\n * A file, as emitted out from FileUploadZone\n */\nexport interface UploadableFileItem {\n file: File\n error: Nullable<Error>\n /**\n * You can use this ID to check for File equality\n */\n id: string\n}\n\nexport enum BlobUploadStatus {\n Success = 1,\n Failure = 2\n}\n\nexport type BlobPostResultItem = {\n blobId?: string\n fileName?: string\n fileSize?: number\n formKey: string\n /**\n * Success = 1, Failure = 2\n */\n uploadStatus: number\n uploadError: string\n}\n\nexport interface UploadFileItem extends UploadableFileItem {\n /**\n * Progress between 0 and 100\n */\n progress: number\n\n /**\n * When upload has finished this contains a BlobPostResultItem\n */\n result: Optional<BlobPostResultItem>\n\n /**\n * When a blob gets assigned to a resource, it should count as in use, and this will\n * prevent it from being deleted as junk\n */\n inUse?: boolean\n}\n\nfunction buildFileTypeSpecifiers(\n accept: Optional<string>\n): Optional<FileTypeSpecifier[]> {\n if (!accept) return undefined\n const specifiers = accept\n .split(',')\n .map((s) => (isFileTypeSpecifier(s) ? s : null))\n .filter((s): s is FileTypeSpecifier => s !== null)\n\n return specifiers.length ? specifiers : undefined\n}\n\nexport function usePrepareUploadableFiles(params: {\n disabled?: MaybeRef<Optional<boolean>>\n accept?: MaybeRef<Optional<string>>\n multiple?: MaybeRef<Optional<boolean>>\n countLimit?: MaybeRef<Optional<number>>\n sizeLimit: MaybeRef<number>\n}) {\n const { disabled, accept, multiple, sizeLimit, countLimit } = params\n\n const fileTypeSpecifiers = computed(() => buildFileTypeSpecifiers(unref(accept)))\n\n const handleFiles = (files: File[]): UploadableFileItem[] => {\n const results: UploadableFileItem[] = []\n const allowedTypes = fileTypeSpecifiers.value\n\n for (const file of files) {\n const id = generateFileId(file)\n const finalCountLimit = !unref(multiple) ? 1 : unref(countLimit)\n\n // skip file, if it's selected twice somehow\n if (results.find((r) => r.id === id)) continue\n\n // Only allow a single file if !multiple\n if (finalCountLimit && results.length >= finalCountLimit) {\n break\n }\n\n if (allowedTypes) {\n const validationResult = validateFileType(file, allowedTypes)\n if (validationResult instanceof Error) {\n results.push({\n file,\n id,\n error: validationResult\n })\n continue\n }\n }\n\n if (file.size > unref(sizeLimit)) {\n results.push({\n file,\n id,\n error: new FileTooLargeError(\n `The selected file's size (${prettyFileSize(\n file.size\n )}) is too big (over ${prettyFileSize(unref(sizeLimit))})`\n )\n })\n continue\n }\n\n results.push({ file, id, error: null })\n }\n\n return results\n }\n\n return {\n /**\n * Validate incoming files and build UploadableFileItem structs out of them\n */\n buildUploadableFiles: (files: File[]) => {\n if (unref(disabled || false)) return\n return handleFiles(files)\n }\n }\n}\n\nclass FileTooLargeError extends BaseError {\n static defaultMessage = \"The selected file's size is too large\"\n}\n\nexport function useFileUploadProgressCore(params: {\n item: MaybeRef<MaybeNullOrUndefined<UploadFileItem>>\n}) {\n const errorMessage = computed(() => {\n const item = unref(params.item)\n if (!item) return null\n\n const itemError = item.error\n if (itemError) return itemError.message\n\n const uploadError = item.result?.uploadError\n if (uploadError) return uploadError\n\n return null\n })\n\n const progressBarColorClass = computed(() => {\n const item = unref(params.item)\n if (errorMessage.value) return 'bg-danger'\n if (item && item.progress >= 100) return 'bg-success'\n return 'bg-primary'\n })\n\n const progressBarClasses = computed(() => {\n return ['h-1', progressBarColorClass.value].join(' ')\n })\n\n const progressBarStyle = computed((): CSSProperties => {\n const item = unref(params.item)\n return {\n width: `${item ? item.progress : 0}%`\n }\n })\n\n return { errorMessage, progressBarClasses, progressBarStyle }\n}\n","<!-- eslint-disable vuejs-accessibility/form-control-has-label -->\n<template>\n <div ref=\"fileUploadZone\" class=\"file-upload-zone\">\n <slot\n :is-dragging-files=\"isOverDropZone\"\n :open-file-picker=\"triggerPicker\"\n :activator-on=\"{ click: triggerPicker }\"\n />\n <input\n ref=\"fileInput\"\n type=\"file\"\n class=\"hidden\"\n :accept=\"accept\"\n :multiple=\"multiple\"\n @click.stop\n @change=\"onInputChange\"\n />\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable vue/require-default-prop */\nimport type { Nullable } from '@speckle/shared'\nimport { useDropZone } from '@vueuse/core'\nimport { computed, ref } from 'vue'\nimport { usePrepareUploadableFiles } from '~~/src/composables/form/fileUpload'\nimport type { UploadableFileItem } from '~~/src/composables/form/fileUpload'\n\nconst emit = defineEmits([\"files-selected\"])\n\nconst props = defineProps({\n accept: null,\n multiple: { type: Boolean },\n sizeLimit: { default: 1024 * 1024 * 100 },\n countLimit: null,\n disabled: { type: Boolean }\n})\n\nconst fileUploadZone = ref(null as Nullable<HTMLDivElement>)\nconst fileInput = ref(null as Nullable<HTMLInputElement>)\n\nconst { buildUploadableFiles } = usePrepareUploadableFiles({\n sizeLimit: computed(() => props.sizeLimit),\n countLimit: computed(() => props.countLimit),\n accept: computed(() => props.accept),\n multiple: computed(() => props.multiple),\n disabled: computed(() => props.disabled)\n})\nconst handleIncomingFiles = (files: File[]) => {\n const fileItems = buildUploadableFiles(files)\n if (!fileItems?.length) return\n emit('files-selected', { files: fileItems })\n}\n\nconst { isOverDropZone } = useDropZone(fileUploadZone, (files) => {\n if (!files?.length) return\n handleIncomingFiles(files)\n})\n\nconst onInputChange = () => {\n const input = fileInput.value\n if (!input) return\n\n const files = [...(input.files || [])]\n input.value = '' // Resetting value\n\n if (!files.length) return\n handleIncomingFiles(files)\n}\n\nconst triggerPicker = () => {\n fileInput.value?.click()\n}\n\ndefineExpose({\n triggerPicker\n})\n</script>\n"],"names":["emit","__emit","props","__props","NuxtLink","resolveDynamicComponent","RouterLink","linkComponent","computed","isObjectLike","buttonType","isDisabled","finalLeftIcon","ArrowPathIcon","bgAndBorderClasses","classParts","foregroundClasses","hasCustomTextColor","roundedClasses","ringClasses","sizeClasses","paddingClasses","generalClasses","decoratorClasses","buttonClasses","isLinkOrText","iconClasses","onClick","e","ToastNotificationType","ToastNotificationType2","isTitleOnly","_a","_b","dismiss","onCtaClick","_c","KEYBOARD_CLICK_CHAR","keyboardClick","cb","badgeColorClasses","badgeDotIconColorClasses","badgeClasses","dotClasses","onIconClick","junkVariable","markClassesUsed","classes","TailwindBreakpoints","useStepsInternals","params","modelValue","steps","orientation","goVerticalBelow","nonInteractive","stepsPadding","finalOrientation","value","clamp","newVal","getStepDisplayValue","step","isCurrentStep","isFinishedStep","switchStep","newStep","stepObj","listClasses","paddingHorizontal","paddingVertical","linkClasses","toRefs","labelClasses","leftMargin","extraListClasses","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_4","_sfc_render","_ctx","_cache","_hoisted_3","isAnimating","ref","mousePosition","isClicked","animationDuration","isMouseVisible","dynamicSlots","delay","action","wait","toggleSlotVisibility","slotToToggle","slot","handleAction","onMounted","onBeforeUnmount","computedClasses","generateRandomId","prefix","nanoid","checkboxValue","coreChecked","errorMessage","handleChange","coreValue","useField","title","descriptionText","descriptionId","descriptionClasses","implicitId","finalId","onChange","newModelValue","newCoreValue","shouldBeChecked","isCoreChecked","radioValue","useTextInputCore","inputEl","options","error","unref","coreInputClasses","coreClasses","color","internalHelpTipId","base","hideHelpTip","helpTip","hasHelpTip","helpTipId","helpTipClasses","focus","clear","isArray","inputElement","__expose","slots","useSlots","leadingIconClasses","hasLeadingIcon","VALID_HTTP_URL","VALID_EMAIL","isEmail","val","isOneOrMultipleEmails","i","isRequired","isString","isSameAs","otherFieldName","otherFieldDisplayName","meta","isStringOfLength","minLength","maxLength","isNullOrUndefined","isUndefined","stringContains","match","message","isUrl","isItemSelected","useWrappingContainerHiddenCount","skipCalculation","elementToWatchForChanges","itemContainer","trackResize","trackMutations","hiddenItemCount","recalculate","target","avatarElements","visibleCount","totalCount","firstElOffsetTop","avatarEl","offsetTop","useResizeObserver","useMutationObserver","useFormSelectChildInternals","dynamicVisibility","selectedValue","currentValue","isArrayValue","v","isObjectLikeType","isMounted","useMounted","searchInput","menuEl","listboxButton","searchValue","currentItems","isAsyncLoading","forceUpdateKey","listboxButtonBounding","useElementBounding","useIntersectionObserver","isIntersecting","renderClearButton","buttonsWrapperClasses","commonButtonClasses","clearButtonClasses","hasValueSelected","hasSearch","isAsyncSearchMode","wrappedValue","finalValue","currentVal","itemKey","clearValue","finalItems","searchVal","listboxOptionsClasses","listboxOptionsStyle","style","top","left","width","height","simpleDisplayText","triggerSearch","debouncedSearch","debounce","listboxOptionClasses","active","disabled","hideCheckmarks","watch","newItems","hiddenSelectedItemCount","isMultiItemArrayValue","firstItem","searchFilterPredicate","search","deselectItem","item","enabled","_useModel","copy","useClipboard","copied","handleCopy","selectAllText","event","textElement","selection","range","ModifierKeys","clientOs","getClientOperatingSystem","ModifierKeyTitles","OperatingSystem","getKeyboardShortcutTitle","keys","isModifierKey","k","onKeyboardShortcut","modifiers","args","onKeyDown","isAltOrOpt","isCtrlOrCmd","isShift","modifier","useFormCheckboxModel","model","isChecked","scrolledFromTop","scrolledToBottom","isForm","hasButtons","hasTitle","open","maxWidthWeight","widthClasses","onClose","onScroll","throttle","scrollTop","offsetHeight","scrollHeight","content","contentHeight","isExpanded","backgroundClass","titleClasses","toggleExpansion","nextTick","panelClasses","GridListToggleValue","ThrottleOrDebounce","ThrottleOrDebounce2","HorizontalDirection","HorizontalDirection2","useWindowResizeHandler","handler","isClient","throttleOrDebounce","finalHandler","useOnBeforeWindowUnload","useResponsiveHorizontalDirectionCalculation","el","defaultDirection","direction","stopUpdatesBelowWidth","element","recalculateDirection","rect","showOnLeftSide","showOnRightSide","menuItems","menuDirection","menuButton","isOpenInternally","finalOpen","buildButtonClassses","chooseItem","toggle","processOpen","isOpen","oldVal","shouldBeOpen","activeItemId","activeItem","onTabClick","buttonContainer","activeItemRef","id","parent","b","borderStyle","setActiveItem","paddingRightStyle","buttonCount","padding","rowsWrapperClasses","getHeaderClasses","column","c","getClasses","colIndex","columnClass","handleRowClick","wrapper","initializeLoader","int","secondarySlotPaddingClasses","defaultSlotPaddingClasses","hasDescription","icon","InformationCircleIcon","ExclamationCircleIcon","XCircleIcon","CheckCircleIcon","containerClasses","subcontainerClasses","mainContentContainerClasses","descriptionWrapperClasses","actionsContainerClasses","hasDescriptionAndActions","textClasses","actionSize","writableAsyncComputed","get","initialState","readOptions","set","asyncRead","debugging","logSettings","getTrace","logger","finalGet","res","finalSet","readValue","computedAsync","getter","buildManualPromise","resolve","reject","rej","provides","getCurrentInstance","ctxKey","s","state","inject","isInputEvent","isInputFocused","useFocus","ctxManager","autocompleteItems","isAutocompleteLoading","isAutocompleteOpen","query","selectedItems","uniq","t","shouldShowClear","inputWrapperClasses","removeTag","tag","idx","newSelected","onQueryEscape","onQueryBackspace","newTags","onQueryArrowUp","onQueryArrowDown","resolveAutocompleteItems","debouncedResolve","debouncedResolveAndMarkLoading","onQueryInput","forceCreateFromInput","selected","newTag","tagExists","newIsOpen","oldIsOpen","useAvatarSizeClasses","heightClasses","initials","parts","firstLetter","secondLetter","borderClasses","bgClasses","hoverClasses","activeClasses","maxCountHiddenItemCount","finalHiddenItemCount","items","LazyUserAvatarEditor","defineAsyncComponent","CommonLoadingIcon","editMode","modelAsUser","onSave","newUrl","BaseError","__publicField","LogicError","UninitializedResourceAccessError","ComposableInvokedOutOfScopeError","UnsupportedEnvironmentError","UniqueFileTypeSpecifier","validateFileType","file","allowedTypes","allowedUniqueTypes","intersection","allowedUniqueType","allowedExtensions","difference","fileExt","resolveFileExtension","MissingFileExtensionError","allowedExtension","ForbiddenFileTypeError","fileName","ext","isFileTypeSpecifier","type","prettyFileSize","sizeInBytes","removeTrailingZeroes","fileSize","kbSize","mbSize","gbSize","generateFileId","importantData","md5","BlobUploadStatus","buildFileTypeSpecifiers","accept","specifiers","usePrepareUploadableFiles","multiple","sizeLimit","countLimit","fileTypeSpecifiers","handleFiles","files","results","finalCountLimit","r","validationResult","FileTooLargeError","fileUploadZone","fileInput","buildUploadableFiles","handleIncomingFiles","fileItems","isOverDropZone","useDropZone","onInputChange","input","triggerPicker"],"mappings":"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"}
1
+ {"version":3,"file":"lib.cjs","sources":["../src/components/form/Button.vue","../src/components/common/text/Link.vue","../src/helpers/global/toast.ts","../src/components/global/ToastRenderer.vue","../src/helpers/global/accessibility.ts","../src/components/common/Badge.vue","../src/helpers/tailwind.ts","../src/composables/common/steps.ts","../src/components/common/steps/Number.vue","../src/components/common/steps/Bullet.vue","../src/components/common/animation/MouseIcon.vue","../src/components/common/animation/ClickIcon.vue","../src/components/common/animation/Instructional.vue","../src/components/form/CardButton.vue","../src/components/form/Checkbox.vue","../src/components/form/Radio.vue","../src/composables/form/textInput.ts","../src/components/form/TextArea.vue","../src/components/form/TextInput.vue","../src/helpers/common/validation.ts","../src/composables/layout/resize.ts","../src/composables/form/select.ts","../src/components/form/select/Base.vue","../src/components/form/select/SourceApps.vue","../src/components/form/select/Badges.vue","../src/components/form/Switch.vue","../src/components/form/ClipboardInput.vue","../src/helpers/form/input.ts","../src/composables/form/input.ts","../src/components/layout/Dialog.vue","../src/components/layout/DialogSection.vue","../src/components/layout/Disclosure.vue","../src/helpers/layout/components.ts","../src/components/layout/GridListToggle.vue","../src/composables/common/window.ts","../src/components/layout/Menu.vue","../src/components/layout/Tabs.vue","../src/components/layout/PageTabs.vue","../src/components/layout/Table.vue","../src/components/InfiniteLoading.vue","../src/components/layout/Panel.vue","../src/components/common/Alert.vue","../src/composables/common/async.ts","../src/components/form/tags/ContextManager.vue","../src/components/form/Tags.vue","../src/composables/user/avatar.ts","../src/components/user/Avatar.vue","../src/components/user/AvatarGroup.vue","../src/components/common/loading/Icon.vue","../src/components/user/AvatarEditable.vue","../src/helpers/common/error.ts","../src/helpers/form/file.ts","../src/composables/form/fileUpload.ts","../src/components/form/file-upload/Zone.vue"],"sourcesContent":["<template>\n <Component\n :is=\"to ? linkComponent : 'button'\"\n :href=\"to\"\n :to=\"to\"\n :type=\"buttonType\"\n :external=\"external\"\n :class=\"buttonClasses\"\n :disabled=\"isDisabled\"\n role=\"button\"\n @click=\"onClick\"\n >\n <Component\n :is=\"finalLeftIcon\"\n v-if=\"finalLeftIcon\"\n :class=\"`${iconClasses} ${hideText ? '' : 'mr-2'}`\"\n />\n <slot v-if=\"!hideText\">Button</slot>\n <Component\n :is=\"iconRight\"\n v-if=\"iconRight || !loading\"\n :class=\"`${iconClasses} ${hideText ? '' : 'ml-2'}`\"\n />\n </Component>\n</template>\n<script setup lang=\"ts\">\nimport { isObjectLike } from 'lodash'\nimport type { PropType } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\nimport { computed, resolveDynamicComponent } from 'vue'\nimport type { Nullable, Optional } from '@speckle/shared'\nimport { ArrowPathIcon } from '@heroicons/vue/24/solid'\nimport type { FormButtonColor, FormButtonTextColor } from '~~/src/helpers/form/button'\n\ntype FormButtonSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl'\n\nconst emit = defineEmits([\"click\"])\n\nconst props = defineProps({\n /**\n * URL to which to navigate - can be a relative (app) path or an absolute link for an external URL\n */\n to: {\n type: String as PropType<Optional<string>>,\n required: false,\n default: undefined\n },\n /**\n * Choose from one of many button sizes\n */\n size: {\n type: String as PropType<FormButtonSize>,\n default: 'base'\n },\n /**\n * If set, will make the button take up all available space horizontally\n */\n fullWidth: {\n type: Boolean,\n default: false\n },\n /**\n * Will outline the button.\n */\n outlined: {\n type: Boolean,\n default: false\n },\n /**\n * Will apply a rounded class.\n */\n rounded: {\n type: Boolean,\n default: false\n },\n /**\n * Similar to \"link\", but without an underline and possibly in different colors\n */\n text: {\n type: Boolean,\n default: false\n },\n /**\n * Will remove paddings and background. Use for links.\n */\n link: {\n type: Boolean,\n default: false\n },\n /**\n * Colors:\n * default: the default primary blue.\n * invert: for when you want to use this button on a primary background.\n * danger: for dangerous actions (e.g. deletions).\n * warning: for less dangerous actions (e.g. archival).\n */\n color: {\n type: String as PropType<FormButtonColor>,\n default: 'default'\n },\n /**\n * Text color, only used when color=secondary\n */\n textColor: {\n type: String as PropType<FormButtonTextColor>,\n default: 'default'\n },\n /**\n * Whether the target location should be forcefully treated as an external URL\n * (for relative paths this will likely cause a redirect)\n */\n external: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n /**\n * Whether to disable the button so that it can't be pressed\n */\n disabled: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n /**\n * If set, will have type set to \"submit\" to enable it to submit any parent forms\n */\n submit: {\n type: Boolean,\n default: false\n },\n /**\n * Add icon to the left from the text\n */\n iconLeft: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Add icon to the right from the text\n */\n iconRight: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Hide default slot (when you want to show icons only)\n */\n hideText: {\n type: Boolean,\n default: false\n },\n /**\n * Customize component to be used when rendering links.\n *\n * The component will try to dynamically resolve NuxtLink and RouterLink and use those, if this is set to null.\n */\n linkComponent: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Disables the button and shows a spinning loader\n */\n loading: {\n type: Boolean,\n default: false\n }\n})\n\nconst NuxtLink = resolveDynamicComponent('NuxtLink')\nconst RouterLink = resolveDynamicComponent('RouterLink')\n\nconst linkComponent = computed(() => {\n if (props.linkComponent) return props.linkComponent\n if (props.external) return 'a'\n if (isObjectLike(NuxtLink)) return NuxtLink\n if (isObjectLike(RouterLink)) return RouterLink\n return 'a'\n})\n\nconst buttonType = computed(() => {\n if (props.to) return undefined\n if (props.submit) return 'submit'\n return 'button'\n})\n\nconst isDisabled = computed(() => props.disabled || props.loading)\nconst finalLeftIcon = computed(() => (props.loading ? ArrowPathIcon : props.iconLeft))\n\nconst bgAndBorderClasses = computed(() => {\n const classParts: string[] = []\n\n classParts.push('border-2')\n if (isDisabled.value) {\n classParts.push(\n props.outlined\n ? 'border-foreground-disabled'\n : 'bg-foundation-disabled border-transparent'\n )\n } else {\n switch (props.color) {\n case 'invert':\n classParts.push(\n props.outlined\n ? 'border-foundation dark:border-foreground'\n : 'bg-foundation dark:bg-foreground border-transparent'\n )\n break\n case 'card':\n classParts.push(\n props.outlined\n ? 'border-foundation-2 shadow'\n : 'bg-foundation-2 dark:bg-foundation-2 border-foundation shadow'\n )\n break\n case 'danger':\n classParts.push(props.outlined ? 'border-danger' : 'bg-danger border-danger')\n break\n case 'secondary':\n classParts.push(\n props.outlined ? 'border-foundation' : 'bg-foundation border-foundation-2'\n )\n break\n case 'warning':\n classParts.push(props.outlined ? 'border-warning' : 'bg-warning border-warning')\n break\n case 'info':\n classParts.push(props.outlined ? 'border-info' : 'bg-info border-info')\n break\n case 'success':\n classParts.push(props.outlined ? 'border-success' : 'bg-success border-success')\n break\n case 'default':\n default:\n classParts.push(\n props.outlined\n ? 'border-primary hover:border-primary-focus'\n : 'bg-primary hover:bg-primary-focus border-transparent'\n )\n break\n }\n }\n\n return classParts.join(' ')\n})\n\nconst foregroundClasses = computed(() => {\n const classParts: string[] = []\n const hasCustomTextColor = props.textColor !== 'default'\n\n if (hasCustomTextColor && !isDisabled.value) {\n switch (props.textColor) {\n case 'primary':\n classParts.push('text-primary')\n break\n case 'warning':\n classParts.push('text-warning')\n break\n case 'success':\n classParts.push('text-success')\n break\n case 'danger':\n classParts.push('text-danger')\n break\n case 'info':\n classParts.push('text-info')\n break\n }\n }\n\n if (!props.text && !props.link) {\n if (isDisabled.value) {\n classParts.push('text-foreground-disabled')\n } else if (!hasCustomTextColor) {\n switch (props.color) {\n case 'invert':\n classParts.push(\n props.outlined ? 'text-foundation dark:text-foreground' : 'text-primary'\n )\n break\n case 'card':\n classParts.push(props.outlined ? 'text-foreground' : 'text-foreground')\n break\n case 'danger':\n classParts.push(\n props.outlined ? 'text-danger' : 'text-foundation dark:text-foreground'\n )\n break\n case 'warning':\n classParts.push(\n props.outlined ? 'text-warning' : 'text-foundation dark:text-foreground'\n )\n break\n case 'info':\n classParts.push(\n props.outlined ? 'text-info' : 'text-foundation dark:text-foreground'\n )\n break\n case 'success':\n classParts.push(\n props.outlined ? 'text-success' : 'text-foundation dark:text-foreground'\n )\n break\n case 'secondary':\n classParts.push(\n props.outlined\n ? 'text-foreground hover:text-primary'\n : 'text-foreground hover:text-primary'\n )\n break\n case 'default':\n default:\n classParts.push(\n props.outlined\n ? 'text-primary hover:text-primary-focus'\n : 'text-foundation dark:text-foreground'\n )\n break\n }\n }\n } else {\n if (isDisabled.value) {\n classParts.push('text-foreground-disabled')\n } else if (!hasCustomTextColor) {\n if (props.color === 'invert') {\n classParts.push(\n 'text-foundation hover:text-foundation-2 dark:text-foreground dark:hover:text-foreground'\n )\n } else if (props.color === 'secondary') {\n classParts.push('text-foreground-2 hover:text-primary-focus')\n } else if (props.color === 'success') {\n classParts.push('text-success')\n } else if (props.color === 'warning') {\n classParts.push('text-warning')\n } else if (props.color === 'info') {\n classParts.push('text-info')\n } else if (props.color === 'danger') {\n classParts.push('text-danger')\n } else {\n classParts.push('text-primary hover:text-primary-focus')\n }\n }\n }\n return classParts.join(' ')\n})\n\nconst roundedClasses = computed(() => {\n const classParts: string[] = []\n classParts.push(props.rounded ? 'rounded-full' : 'rounded-md')\n return classParts.join(' ')\n})\n\nconst ringClasses = computed(() => {\n const classParts: string[] = []\n if (!isDisabled.value) {\n switch (props.color) {\n case 'invert':\n classParts.push('hover:ring-4 ring-white/50')\n break\n case 'danger':\n classParts.push('hover:ring-4 ring-danger-lighter dark:ring-danger-darker')\n break\n case 'warning':\n classParts.push('hover:ring-4 ring-warning-lighter dark:ring-warning-darker')\n break\n case 'info':\n classParts.push('hover:ring-4 ring-info-lighter dark:ring-info-darker')\n break\n case 'success':\n classParts.push('hover:ring-4 ring-success-lighter dark:ring-success-darker')\n break\n case 'default':\n default:\n classParts.push('hover:ring-2')\n break\n }\n }\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed(() => {\n switch (props.size) {\n case 'xs':\n return 'h-5 text-xs font-medium xxx-tracking-wide'\n case 'sm':\n return 'h-6 text-sm font-medium xxx-tracking-wide'\n case 'lg':\n return 'h-10 text-lg font-semibold xxx-tracking-wide'\n case 'xl':\n return 'h-14 text-xl font-bold xxx-tracking-wide'\n default:\n case 'base':\n return 'h-8 text-sm sm:text-base font-medium xxx-tracking-wide'\n }\n})\n\nconst paddingClasses = computed(() => {\n switch (props.size) {\n case 'xs':\n return 'px-1'\n case 'sm':\n return 'px-2'\n case 'lg':\n return 'px-4'\n case 'xl':\n return 'px-5'\n default:\n case 'base':\n return 'px-3'\n }\n})\n\nconst generalClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.fullWidth) {\n classParts.push('w-full')\n }\n\n if (isDisabled.value) {\n classParts.push('cursor-not-allowed')\n }\n\n return classParts.join(' ')\n})\n\nconst decoratorClasses = computed(() => {\n const classParts: string[] = []\n if (!isDisabled.value && !props.link && !props.text) {\n classParts.push('active:scale-[0.97]')\n }\n\n if (!isDisabled.value && props.link) {\n classParts.push(\n 'underline decoration-transparent decoration-2 underline-offset-4\thover:decoration-inherit'\n )\n }\n\n return classParts.join(' ')\n})\n\nconst buttonClasses = computed(() => {\n const isLinkOrText = props.link || props.text\n return [\n 'transition inline-flex justify-center text-center items-center outline-none select-none leading-[0.9rem]',\n generalClasses.value,\n sizeClasses.value,\n foregroundClasses.value,\n isLinkOrText ? '' : bgAndBorderClasses.value,\n isLinkOrText ? '' : roundedClasses.value,\n isLinkOrText ? '' : ringClasses.value,\n props.link ? '' : paddingClasses.value,\n decoratorClasses.value\n ].join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['']\n\n if (props.loading) {\n classParts.push('animate-spin')\n }\n\n switch (props.size) {\n case 'xs':\n classParts.push('h-3 w-3')\n break\n case 'sm':\n classParts.push('h-4 w-4')\n break\n case 'lg':\n classParts.push('h-6 w-6')\n break\n case 'xl':\n classParts.push('h-8 w-8')\n break\n case 'base':\n default:\n classParts.push('h-5 w-5')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst onClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n return\n }\n\n emit('click', e)\n}\n</script>\n<style scoped>\n.icon-slot:empty {\n display: none;\n}\n</style>\n","<template>\n <FormButton\n :link=\"!noUnderline\"\n :text=\"noUnderline\"\n :to=\"to\"\n :external=\"external\"\n :disabled=\"disabled\"\n :size=\"size\"\n :foreground-link=\"foregroundLink\"\n :icon-left=\"iconLeft\"\n :icon-right=\"iconRight\"\n :hide-text=\"hideText\"\n role=\"link\"\n @click.capture=\"onClick\"\n >\n <slot>Link</slot>\n </FormButton>\n</template>\n<script setup lang=\"ts\">\nimport FormButton from '~~/src/components/form/Button.vue'\nimport type { PropType } from 'vue'\nimport type { Nullable, Optional } from '@speckle/shared'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype LinkSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl'\nconst emit = defineEmits([\"click\"])\n\nconst props = defineProps({\n to: {\n type: String as PropType<Optional<string>>,\n required: false,\n default: undefined\n },\n external: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n disabled: {\n type: Boolean as PropType<Optional<boolean>>,\n required: false,\n default: undefined\n },\n size: {\n type: String as PropType<LinkSize>,\n default: 'base'\n },\n foregroundLink: {\n type: Boolean,\n default: false\n },\n /**\n * Add icon to the left from the text\n */\n iconLeft: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Add icon to the right from the text\n */\n iconRight: {\n type: [Object, Function] as PropType<Nullable<PropAnyComponent>>,\n default: null\n },\n /**\n * Hide default slot (when you want to show icons only)\n */\n hideText: {\n type: Boolean,\n default: false\n },\n noUnderline: {\n type: Boolean,\n default: false\n }\n})\n\nconst onClick = (e: MouseEvent) => {\n if (props.disabled) {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n return\n }\n\n emit('click', e)\n}\n</script>\n","export enum ToastNotificationType {\n Success,\n Warning,\n Danger,\n Info\n}\n\nexport type ToastNotification = {\n title?: string\n /**\n * Optionally provide extra text\n */\n description?: string\n type: ToastNotificationType\n /**\n * Optionally specify a CTA link on the right\n */\n cta?: {\n title: string\n url?: string\n onClick?: (e: MouseEvent) => void\n }\n /**\n * Whether or not the toast should disappear automatically after a while.\n * Defaults to true\n */\n autoClose?: boolean\n}\n","<template>\n <div\n aria-live=\"assertive\"\n class=\"pointer-events-none fixed inset-0 flex items-end px-4 py-6 mt-10 sm:items-start sm:p-6 z-50\"\n >\n <div class=\"flex w-full flex-col items-center gap-4 sm:items-end\">\n <!-- Notification panel, dynamically insert this into the live region when it needs to be displayed -->\n <Transition\n enter-active-class=\"transform ease-out duration-300 transition\"\n enter-from-class=\"translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-2\"\n enter-to-class=\"translate-y-0 opacity-100 sm:translate-x-0\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"notification\"\n class=\"pointer-events-auto w-full max-w-[20rem] overflow-hidden rounded-lg bg-foundation text-foreground shadow-lg ring-1 ring-primary-muted ring-opacity-5\"\n :class=\"isTitleOnly ? 'p-2' : 'p-3'\"\n >\n <div class=\"flex gap-2\" :class=\"isTitleOnly ? 'items-center' : 'items-start'\">\n <div class=\"flex-shrink-0\">\n <CheckCircleIcon\n v-if=\"notification.type === ToastNotificationType.Success\"\n class=\"text-success\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n <XCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Danger\"\n class=\"text-danger\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n <ExclamationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Warning\"\n class=\"text-warning\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n <InformationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Info\"\n class=\"text-info\"\n :class=\"isTitleOnly ? 'h-5 w-5' : 'h-6 w-6'\"\n aria-hidden=\"true\"\n />\n </div>\n <div class=\"w-full min-w-[10rem]\">\n <p\n v-if=\"notification.title\"\n class=\"text-foreground font-bold\"\n :class=\"isTitleOnly ? 'text-sm' : 'text-base'\"\n >\n {{ notification.title }}\n </p>\n <p\n v-if=\"notification.description\"\n class=\"label label--light text-foreground-2 text-sm\"\n >\n {{ notification.description }}\n </p>\n <div v-if=\"notification.cta\">\n <CommonTextLink\n :to=\"notification.cta.url\"\n class=\"label\"\n size=\"xs\"\n primary\n @click=\"onCtaClick\"\n >\n {{ notification.cta.title }}\n </CommonTextLink>\n </div>\n </div>\n <div class=\"ml-2 flex-shrink-0\" :class=\"isTitleOnly ? 'mt-1.5' : ''\">\n <button\n type=\"button\"\n class=\"inline-flex rounded-md bg-foundation text-foreground-2 hover:text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2\"\n @click=\"dismiss\"\n >\n <span class=\"sr-only\">Close</span>\n <XMarkIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport CommonTextLink from '~~/src/components/common/text/Link.vue'\nimport {\n CheckCircleIcon,\n XCircleIcon,\n ExclamationCircleIcon,\n InformationCircleIcon\n} from '@heroicons/vue/24/outline'\nimport { XMarkIcon } from '@heroicons/vue/20/solid'\nimport { computed } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport { ToastNotificationType } from '~~/src/helpers/global/toast'\nimport type { ToastNotification } from '~~/src/helpers/global/toast'\n\nconst emit = defineEmits([\"update:notification\"])\n\nconst props = defineProps({\n notification: null\n})\n\nconst isTitleOnly = computed(\n () => !props.notification?.description && !props.notification?.cta\n)\n\nconst dismiss = () => {\n emit('update:notification', null)\n}\n\nconst onCtaClick = (e: MouseEvent) => {\n props.notification?.cta?.onClick?.(e)\n dismiss()\n}\n</script>\n","const KEYBOARD_CLICK_CHAR = 'Enter'\n\n/**\n * Visible, non-interactive elements with click handlers must have at least one keyboard listener for accessibility.\n * You can wrap your click handler with this in @keypress, to run it when enter is pressed on the selected component\n * See more: https://github.com/vue-a11y/eslint-plugin-vuejs-accessibility/blob/main/docs/click-events-have-key-events.md\n */\nexport function keyboardClick(cb: (e: KeyboardEvent) => void) {\n return (e: KeyboardEvent) => {\n if (e.code !== KEYBOARD_CLICK_CHAR) return\n cb(e)\n }\n}\n","<template>\n <span :class=\"badgeClasses\">\n <svg v-if=\"dot\" :class=\"dotClasses\" fill=\"currentColor\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n <slot>Badge</slot>\n <button v-if=\"iconLeft\" :class=\"iconClasses\" @click=\"onIconClick($event)\">\n <Component :is=\"iconLeft\" :class=\"['h-4 w-4', badgeDotIconColorClasses]\" />\n </button>\n </span>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype BadgeSize = 'base' | 'lg'\n\nconst emit = defineEmits([\"click-icon\"])\n\nconst props = defineProps({\n size: null,\n colorClasses: null,\n dot: { type: Boolean },\n dotIconColorClasses: null,\n iconLeft: null,\n rounded: { type: Boolean },\n clickableIcon: { type: Boolean }\n})\n\nconst badgeColorClasses = computed(\n () => props.colorClasses || 'bg-blue-100 text-blue-800'\n)\n\nconst badgeDotIconColorClasses = computed(\n () => props.dotIconColorClasses || 'text-blue-400'\n)\n\nconst badgeClasses = computed(() => {\n const classParts: string[] = [\n 'inline-flex items-center',\n badgeColorClasses.value,\n props.size === 'lg' ? 'px-3 py-0.5 label' : 'px-2.5 py-0.5 caption font-medium'\n ]\n\n if (props.rounded) {\n classParts.push('rounded')\n classParts.push(\n props.size === 'lg' ? 'px-2 py-0.5 label' : 'px-2.5 py-0.5 caption font-medium'\n )\n } else {\n classParts.push('rounded-full')\n classParts.push(\n props.size === 'lg' ? 'px-2.5 py-0.5 label' : 'px-2.5 py-0.5 caption font-medium'\n )\n }\n\n return classParts.join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = [\n 'mt-0.5 ml-0.5 inline-flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-full focus:outline-none'\n ]\n\n if (props.clickableIcon) {\n classParts.push('cursor-pointer')\n } else {\n classParts.push('cursor-default')\n }\n\n return classParts.join(' ')\n})\n\nconst dotClasses = computed(() => {\n const classParts: string[] = [\n '-ml-0.5 mr-1.5 h-2 w-2',\n badgeDotIconColorClasses.value\n ]\n\n return classParts.join(' ')\n})\n\nconst onIconClick = (e: MouseEvent) => {\n if (!props.clickableIcon) {\n e.stopPropagation()\n e.stopImmediatePropagation()\n e.preventDefault()\n return\n }\n\n emit('click-icon', e)\n}\n</script>\n","let junkVariable: string[] = []\n\n/**\n * If you use concatenation or variables to build tailwind classes, PurgeCSS won't pick up on them\n * during build and will not add them to the build. So you can use this function to just add string\n * literals of tailwind classes so PurgeCSS picks up on them.\n *\n * While you could just define an unused array of these classes, eslint/TS will bother you about the unused\n * variable so it's better to use this instead.\n */\nexport function markClassesUsed(classes: string[]) {\n // this doesn't do anything, except trick the compiler into thinking this isn't a pure\n // function so that the invocations aren't tree-shaken out\n junkVariable = junkVariable ? classes : classes.slice()\n}\n\n/**\n * Default tailwind breakpoint set. Each value is the minimum width (in pixels) expected for each breakpoint.\n */\nexport enum TailwindBreakpoints {\n sm = 640,\n md = 746,\n lg = 1024,\n xl = 1280,\n '2xl' = 1536\n}\n","import { computed } from 'vue'\nimport type { ToRefs } from 'vue'\nimport type {\n HorizontalOrVertical,\n StepCoreType\n} from '~~/src/helpers/common/components'\nimport { clamp } from 'lodash'\nimport { TailwindBreakpoints, markClassesUsed } from '~~/src/helpers/tailwind'\n\nexport type StepsPadding = 'base' | 'xs' | 'sm'\n\nexport function useStepsInternals(params: {\n props: ToRefs<{\n orientation?: HorizontalOrVertical\n steps: StepCoreType[]\n modelValue?: number\n goVerticalBelow?: TailwindBreakpoints\n nonInteractive?: boolean\n stepsPadding?: StepsPadding\n }>\n emit: {\n (e: 'update:modelValue', val: number): void\n }\n}) {\n const {\n props: {\n modelValue,\n steps,\n orientation,\n goVerticalBelow,\n nonInteractive,\n stepsPadding\n },\n emit\n } = params\n\n const finalOrientation = computed(\n (): HorizontalOrVertical =>\n orientation?.value === 'vertical' ? 'vertical' : 'horizontal'\n )\n\n const value = computed({\n get: () => clamp(modelValue?.value || 0, -1, steps.value.length),\n set: (newVal) => emit('update:modelValue', clamp(newVal, 0, steps.value.length))\n })\n\n const getStepDisplayValue = (step: number) => `${step + 1}`\n const isCurrentStep = (step: number) => step === value.value\n const isFinishedStep = (step: number) => step < value.value\n\n const switchStep = (newStep: number, e?: MouseEvent) => {\n if (nonInteractive?.value) {\n e?.preventDefault()\n e?.stopPropagation()\n e?.stopImmediatePropagation()\n return\n }\n\n value.value = newStep\n\n const stepObj = steps.value[value.value]\n stepObj?.onClick?.()\n }\n\n const listClasses = computed(() => {\n const classParts: string[] = ['flex']\n\n let paddingHorizontal: string\n let paddingVertical: string\n if (stepsPadding?.value === 'xs') {\n paddingHorizontal = 'space-x-2'\n paddingVertical = 'space-y-1'\n } else if (stepsPadding?.value === 'sm') {\n paddingHorizontal = 'space-x-4'\n paddingVertical = 'space-y-1'\n } else {\n paddingHorizontal = 'space-x-8'\n paddingVertical = 'space-y-4'\n }\n\n classParts.push('flex')\n if (finalOrientation.value === 'vertical' || goVerticalBelow?.value) {\n classParts.push(`flex-col ${paddingVertical} justify-center`)\n\n if (goVerticalBelow?.value === TailwindBreakpoints.sm) {\n classParts.push(\n `sm:flex-row sm:space-y-0 sm:justify-start sm:${paddingHorizontal} sm:items-center`\n )\n } else if (goVerticalBelow?.value === TailwindBreakpoints.md) {\n classParts.push(\n `md:flex-row md:space-y-0 md:justify-start md:${paddingHorizontal} md:items-center`\n )\n } else if (goVerticalBelow?.value === TailwindBreakpoints.lg) {\n classParts.push(\n `lg:flex-row lg:space-y-0 lg:justify-start lg:${paddingHorizontal} lg:items-center`\n )\n } else if (goVerticalBelow?.value === TailwindBreakpoints.xl) {\n classParts.push(\n `xl:flex-row xl:space-y-0 xl:justify-start xl:${paddingHorizontal} xl:items-center`\n )\n }\n } else {\n classParts.push(`flex-row ${paddingHorizontal} items-center`)\n }\n\n return classParts.join(' ')\n })\n\n const linkClasses = computed(() => {\n const classParts: string[] = ['flex items-center']\n\n if (!nonInteractive?.value) {\n classParts.push('cursor-pointer')\n }\n\n return classParts.join(' ')\n })\n\n return {\n value,\n isCurrentStep,\n isFinishedStep,\n switchStep,\n getStepDisplayValue,\n listClasses,\n linkClasses,\n orientation: finalOrientation\n }\n}\n\n// to allow for dynamic class building above:\nmarkClassesUsed([\n 'sm:space-x-8',\n 'md:space-x-8',\n 'lg:space-x-8',\n 'xl:space-x-8',\n 'sm:space-x-2',\n 'md:space-x-2',\n 'lg:space-x-2',\n 'xl:space-x-2',\n 'sm:space-x-4',\n 'md:space-x-4',\n 'lg:space-x-4',\n 'xl:space-x-4'\n])\n","<template>\n <nav class=\"flex justify-center\" :aria-label=\"ariaLabel || 'Progress steps'\">\n <ol :class=\"listClasses\">\n <li v-for=\"(step, i) in steps\" :key=\"step.name\">\n <a\n v-if=\"isFinishedStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"flex space-x-3 items-center text-primary-focus normal font-medium leading-5\"\n >\n <div\n class=\"shrink-0 h-8 w-8 rounded-full bg-primary-focus text-foreground-on-primary inline-flex items-center justify-center\"\n >\n <CheckIcon class=\"w-5 h-5\" />\n </div>\n <div class=\"flex flex-col\">\n <div>{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"label label--light text-foreground\">\n {{ step.description }}\n </div>\n </div>\n </div>\n </a>\n <a\n v-else-if=\"isCurrentStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n aria-current=\"step\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"flex space-x-3 items-center text-primary-focus normal font-medium leading-5\"\n >\n <div\n class=\"shrink-0 h-8 w-8 rounded-full border-2 border-primary-focus inline-flex items-center justify-center\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div>{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"label label--light text-foreground\">\n {{ step.description }}\n </div>\n </div>\n </div>\n </a>\n <a\n v-else\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"flex space-x-3 items-center text-foreground-disabled normal font-medium leading-5\"\n >\n <div\n class=\"shrink-0 h-8 w-8 rounded-full border-2 border-foreground-disabled inline-flex items-center justify-center\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div>{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"label label--light\">\n {{ step.description }}\n </div>\n </div>\n </div>\n </a>\n </li>\n </ol>\n </nav>\n</template>\n<script setup lang=\"ts\">\nimport { CheckIcon } from '@heroicons/vue/20/solid'\nimport { toRefs } from 'vue'\nimport { useStepsInternals } from '~~/src/composables/common/steps'\nimport type { StepsPadding } from '~~/src/composables/common/steps'\nimport type {\n HorizontalOrVertical,\n NumberStepType\n} from '~~/src/helpers/common/components'\nimport { TailwindBreakpoints } from '~~/src/helpers/tailwind'\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n ariaLabel: null,\n orientation: null,\n steps: null,\n modelValue: null,\n goVerticalBelow: null,\n nonInteractive: { type: Boolean },\n stepsPadding: null\n})\n\nconst {\n isCurrentStep,\n isFinishedStep,\n switchStep,\n getStepDisplayValue,\n listClasses,\n linkClasses\n} = useStepsInternals({\n props: toRefs(props),\n emit\n})\n</script>\n","<template>\n <nav class=\"flex justify-center\" :aria-label=\"ariaLabel || 'Progress steps'\">\n <ol :class=\"[listClasses, extraListClasses]\">\n <li v-for=\"(step, i) in steps\" :key=\"step.name\">\n <a\n v-if=\"isFinishedStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <span class=\"relative flex h-5 w-5 flex-shrink-0 items-center justify-center\">\n <span v-if=\"basic\" class=\"h-3 w-3 rounded-full bg-foreground-2\" />\n <CheckCircleIcon\n v-else\n class=\"h-full w-full text-primary\"\n aria-hidden=\"true\"\n />\n </span>\n <span :class=\"['text-foreground', labelClasses]\">\n {{ step.name }}\n </span>\n </a>\n <a\n v-else-if=\"isCurrentStep(i)\"\n :href=\"step.href\"\n :class=\"linkClasses\"\n aria-current=\"step\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <span\n class=\"relative flex h-5 w-5 flex-shrink-0 items-center justify-center\"\n aria-hidden=\"true\"\n >\n <template v-if=\"basic\">\n <span class=\"h-3 w-3 rounded-full bg-foreground\" />\n </template>\n <template v-else>\n <span class=\"absolute h-4 w-4 rounded-full bg-outline-2\" />\n <span class=\"relative block h-2 w-2 rounded-full bg-primary-focus\" />\n </template>\n </span>\n <span :class=\"['text-primary-focus', labelClasses]\">\n {{ step.name }}\n </span>\n </a>\n <a\n v-else\n :href=\"step.href\"\n :class=\"linkClasses\"\n @click=\"(e) => switchStep(i, e)\"\n >\n <div\n class=\"relative flex h-5 w-5 flex-shrink-0 items-center justify-center\"\n aria-hidden=\"true\"\n >\n <span v-if=\"basic\" class=\"h-3 w-3 rounded-full bg-foreground-2\" />\n <div v-else class=\"h-4 w-4 rounded-full bg-foreground-disabled\" />\n </div>\n <p :class=\"['text-foreground-disabled', labelClasses]\">\n {{ step.name }}\n </p>\n </a>\n </li>\n </ol>\n </nav>\n</template>\n<script setup lang=\"ts\">\nimport { CheckCircleIcon } from '@heroicons/vue/20/solid'\nimport { computed, toRefs } from 'vue'\nimport { useStepsInternals } from '~~/src/composables/common/steps'\nimport type { StepsPadding } from '~~/src/composables/common/steps'\nimport type {\n BulletStepType,\n HorizontalOrVertical\n} from '~~/src/helpers/common/components'\nimport { TailwindBreakpoints } from '~~/src/helpers/tailwind'\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n ariaLabel: null,\n basic: { type: Boolean },\n orientation: null,\n steps: null,\n modelValue: null,\n goVerticalBelow: null,\n nonInteractive: { type: Boolean },\n stepsPadding: null\n})\n\nconst { isCurrentStep, isFinishedStep, switchStep, listClasses, linkClasses } =\n useStepsInternals({\n props: toRefs(props),\n emit\n })\n\nconst labelClasses = computed(() => {\n const classParts: string[] = ['h6 font-medium leading-7']\n\n let leftMargin: string\n if (props.stepsPadding === 'xs') {\n leftMargin = 'ml-1'\n } else if (props.stepsPadding === 'sm') {\n leftMargin = 'ml-2'\n } else {\n leftMargin = 'ml-3'\n }\n\n classParts.push(leftMargin)\n\n if (props.basic) {\n classParts.push('sr-only')\n }\n\n return classParts.join(' ')\n})\n\nconst extraListClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.basic) {\n classParts.push('basic')\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"icon icon-tabler icon-tabler-pointer\"\n width=\"44\"\n height=\"44\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n fill=\"rgba(255,255,255,0.8)\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path stroke=\"none\" d=\"M0 0h24v24H0z\" fill=\"none\" />\n <path\n d=\"M7.904 17.563a1.2 1.2 0 0 0 2.228 .308l2.09 -3.093l4.907 4.907a1.067 1.067 0 0 0 1.509 0l1.047 -1.047a1.067 1.067 0 0 0 0 -1.509l-4.907 -4.907l3.113 -2.09a1.2 1.2 0 0 0 -.309 -2.228l-13.582 -3.904l3.904 13.563z\"\n />\n </svg>\n</template>\n","<template>\n <svg viewBox=\"0 0 18 17\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path\n d=\"M9 1.25V3.5M14.834 3.666L13.243 5.257M17.25 9.5H15M4.757 13.743L3.167 15.333M3 9.5H0.75M4.757 5.257L3.167 3.667\"\n stroke=\"currentColor\"\n stroke-width=\"1\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n","<template>\n <div\n class=\"relative aspect-square w-full h-full max-w-[250px] mx-auto mb-8 border-t border-r border-outline-3 select-none\"\n >\n <div\n class=\"absolute z-50 text-foreground dark:text-foundation\"\n :style=\"{\n transitionProperty: 'all',\n top: mousePosition.top + '%',\n left: mousePosition.left + '%',\n transitionDuration: animationDuration + 'ms'\n }\"\n >\n <ClickIcon\n class=\"absolute -top-5 -left-4 h-12 w-12 -rotate-12 text-foreground\"\n :class=\"[{ hidden: !isClicked }]\"\n />\n <MouseIcon class=\"absolute inset-0 h-11 w-11\" />\n </div>\n <div class=\"w-full h-full overflow-hidden\">\n <slot name=\"background\"></slot>\n <template v-for=\"slotObject in dynamicSlots\" :key=\"slotObject.name\">\n <template v-if=\"slotObject.visible\">\n <slot :name=\"slotObject.name\"></slot>\n </template>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, defineProps, type PropType, onBeforeUnmount } from 'vue'\nimport MouseIcon from '~~/src/components/common/animation/MouseIcon.vue'\nimport ClickIcon from '~~/src/components/common/animation/ClickIcon.vue'\nimport { wait } from '@speckle/shared'\n\ntype AnimationAction = {\n type: 'animation'\n top: number\n left: number\n duration: number\n}\n\ntype ClickAction = {\n type: 'click'\n}\n\ntype DelayAction = {\n type: 'delay'\n duration: number\n}\n\ntype SlotAction = {\n type: 'slot'\n slot: string\n}\n\ntype Action = AnimationAction | ClickAction | SlotAction | DelayAction\n\nconst props = defineProps({\n actions: Array as PropType<Action[]>,\n initialPosition: {\n type: Object as PropType<{ top: number; left: number }>\n },\n slotsConfig: Array as PropType<{ name: string; visible: boolean }[]>\n})\n\nconst isAnimating = ref(true)\nconst mousePosition = ref({ ...props.initialPosition })\nconst isClicked = ref(false)\nconst animationDuration = ref(500)\nconst isMouseVisible = ref(true)\nconst dynamicSlots = ref(props.slotsConfig || [])\n\nasync function delay(action: DelayAction) {\n await wait(action.duration)\n}\n\nfunction toggleSlotVisibility(action: SlotAction) {\n const slotToToggle = dynamicSlots.value.find((slot) => slot.name === action.slot)\n if (slotToToggle) {\n slotToToggle.visible = !slotToToggle.visible\n }\n}\n\nfunction handleAction(action: Action) {\n switch (action.type) {\n case 'animation':\n mousePosition.value = { top: action.top, left: action.left }\n animationDuration.value = action.duration\n break\n case 'click':\n isClicked.value = true\n setTimeout(() => (isClicked.value = false), 500)\n break\n case 'delay':\n return delay(action)\n case 'slot':\n toggleSlotVisibility(action as SlotAction)\n break\n }\n}\n\nonMounted(() => {\n const loopActions = async () => {\n while (isAnimating.value) {\n await delay({ type: 'delay', duration: 800 })\n isMouseVisible.value = true\n for (const action of props.actions || []) {\n await handleAction(action)\n }\n isMouseVisible.value = false\n mousePosition.value = { ...props.initialPosition }\n await delay({ type: 'delay', duration: 200 })\n }\n }\n\n loopActions()\n})\n\nonBeforeUnmount(() => {\n isAnimating.value = false\n})\n</script>\n","<template>\n <button :class=\"computedClasses\" :disabled=\"disabled\" @click=\"onClick\">\n <slot>Text</slot>\n </button>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst emit = defineEmits([\"update:modelValue\", \"click\"])\n\nconst props = defineProps({\n disabled: { type: Boolean },\n modelValue: { type: Boolean }\n})\n\nconst computedClasses = computed(() => {\n const classParts: string[] = [\n 'h-20 bg-foundation-2 inline-flex justify-center items-center outline-none',\n 'normal px-16 py-5 shadow rounded transition active:scale-95'\n ]\n\n if (props.disabled) {\n classParts.push('bg-foundation-disabled text-foreground-2 cursor-not-allowed')\n } else {\n classParts.push(\n props.modelValue\n ? 'bg-primary-focus text-foreground-on-primary'\n : 'bg-foundation text-foreground'\n )\n classParts.push('ring-outline-2 hover:ring-4')\n }\n\n return classParts.join(' ')\n})\n\nconst onClick = (e: MouseEvent) => {\n if (props.disabled) {\n e.preventDefault()\n e.stopPropagation()\n e.stopImmediatePropagation()\n return\n }\n\n emit('update:modelValue', !props.modelValue)\n emit('click', e)\n}\n</script>\n","<template>\n <div class=\"relative flex items-start\">\n <div class=\"flex h-6 items-center\">\n <!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->\n <input\n :id=\"finalId\"\n :checked=\"coreChecked\"\n :aria-describedby=\"descriptionId\"\n :name=\"name\"\n :disabled=\"disabled\"\n :value=\"checkboxValue\"\n type=\"checkbox\"\n class=\"h-4 w-4 rounded text-primary focus:ring-primary bg-foundation disabled:cursor-not-allowed disabled:bg-disabled disabled:text-disabled-2\"\n :class=\"computedClasses\"\n v-bind=\"$attrs\"\n @change=\"onChange\"\n />\n </div>\n <div class=\"ml-2 text-sm\" style=\"padding-top: 2px\">\n <label\n :for=\"finalId\"\n class=\"font-medium text-foreground\"\n :class=\"{ 'sr-only': hideLabel }\"\n >\n <span>{{ title }}</span>\n <span v-if=\"showRequired\" class=\"text-danger ml-1\">*</span>\n </label>\n <p v-if=\"descriptionText\" :id=\"descriptionId\" :class=\"descriptionClasses\">\n {{ descriptionText }}\n </p>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, onMounted, ref } from 'vue'\nimport type { PropType } from 'vue'\nimport type { Optional } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\n\n/**\n * Troubleshooting:\n * - If clicking on the checkbox doesn't do anything, check if any of its ancestor elements\n * have a @click.prevent on them anywhere.\n * - If you're not using the checkbox in a group, it's suggested that you set :value=\"true\",\n * so that a v-model attached to the checkbox will be either 'true' or 'undefined' depending on the\n * checked state\n */\n\ntype ValueType = Optional<string | true> | string[]\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst props = defineProps({\n /**\n * Input name/id. In a checkbox group, all checkboxes must have the same name and different values.\n */\n name: {\n type: String,\n required: true\n },\n /**\n * Whether the input is disabled\n */\n disabled: {\n type: Boolean,\n default: false\n },\n /**\n * Set label text\n */\n label: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Help text\n */\n description: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Whether to inline the help description\n */\n inlineDescription: {\n type: Boolean,\n default: false\n },\n /**\n * vee-validate validation rules\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<ValueType>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Checkbox group's value\n */\n modelValue: {\n type: [String, Boolean] as PropType<ValueType | false>,\n default: undefined\n },\n /**\n * Checkbox's own value. If it is checked, modelValue will include this value (amongst any other checked values from the same group).\n * If not set will default to 'name' value.\n */\n value: {\n type: [String, Boolean] as PropType<Optional<string | true>>,\n default: true\n },\n /**\n * HTML ID to use, must be globally unique. If not specified, a random ID will be generated. One is necessary to properly associate the label and checkbox.\n */\n id: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n hideLabel: {\n type: Boolean,\n default: false\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits([\"update:modelValue\"])\n\nconst checkboxValue = computed(() => props.value || props.name)\n\nconst {\n checked: coreChecked,\n errorMessage,\n handleChange,\n value: coreValue\n} = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n type: 'checkbox',\n checkedValue: checkboxValue,\n initialValue: props.modelValue || undefined\n})\n\nconst title = computed(() => props.label || props.name)\n\nconst computedClasses = computed((): string => {\n return errorMessage.value ? 'border-danger-lighter' : 'border-foreground-4 '\n})\n\nconst descriptionText = computed(() => props.description || errorMessage.value)\nconst descriptionId = computed(() => `${props.name}-description`)\nconst descriptionClasses = computed((): string => {\n const classParts: string[] = []\n\n if (props.inlineDescription) {\n classParts.push('inline ml-2')\n } else {\n classParts.push('block')\n }\n\n if (errorMessage.value) {\n classParts.push('text-danger')\n } else {\n classParts.push('text-foreground-2')\n }\n\n return classParts.join(' ')\n})\n\nconst implicitId = ref<Optional<string>>(generateRandomId('checkbox'))\nconst finalId = computed(() => props.id || implicitId.value)\n\nconst onChange = (e: unknown) => {\n if (props.disabled) return\n handleChange(e)\n}\n\n/**\n * Bugfix for strange issue where checkbox appears checked even tho it shouldnt be.\n * It's not clear why this happens, but for some reason coreValue.value shows that the checkbox\n * is checked, even tho props.modelValue is undefined.\n */\nonMounted(() => {\n const newModelValue = props.modelValue\n const newCoreValue = coreValue.value\n\n const shouldBeChecked = Array.isArray(newModelValue)\n ? newModelValue.includes(props.value as any)\n : newModelValue === props.value\n\n const isCoreChecked = Array.isArray(newCoreValue)\n ? newCoreValue.includes(props.value as any)\n : newCoreValue === props.value\n\n if (shouldBeChecked !== isCoreChecked) {\n handleChange(newModelValue)\n }\n})\n</script>\n","<template>\n <div\n class=\"relative flex gap-2 mb-2 last:mb-0\"\n :class=\"description && inlineDescription ? 'items-start' : 'items-center'\"\n >\n <div class=\"flex h-6 items-center\">\n <!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->\n <input\n :id=\"finalId\"\n :checked=\"coreChecked\"\n :aria-describedby=\"descriptionId\"\n :name=\"name\"\n :disabled=\"disabled\"\n :value=\"radioValue\"\n type=\"radio\"\n class=\"h-4 w-4 rounded-full text-primary focus:ring-primary bg-foundation disabled:cursor-not-allowed disabled:bg-disabled disabled:text-disabled-2\"\n :class=\"computedClasses\"\n v-bind=\"$attrs\"\n @change=\"onChange\"\n />\n </div>\n <div\n class=\"text-xs sm:text-sm\"\n :class=\"inlineDescription ? 'flex gap-2 items-center' : ''\"\n >\n <label\n :for=\"finalId\"\n class=\"text-foreground flex gap-2 items-center\"\n :class=\"{ 'sr-only': hideLabel }\"\n >\n <div v-if=\"icon\" class=\"text-sm\">\n <component :is=\"icon\" class=\"h-8 sm:h-10 w-8 sm:w-10\"></component>\n </div>\n <div class=\"flex flex-col\">\n <span>{{ title }}</span>\n <p\n v-if=\"descriptionText && !inlineDescription\"\n :id=\"descriptionId\"\n :class=\"descriptionClasses\"\n >\n {{ descriptionText }}\n </p>\n </div>\n <span v-if=\"showRequired\" class=\"text-danger ml-1\">*</span>\n </label>\n <p\n v-if=\"descriptionText && inlineDescription\"\n :id=\"descriptionId\"\n :class=\"descriptionClasses\"\n >\n {{ descriptionText }}\n </p>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, onMounted, ref } from 'vue'\nimport type { PropType, ConcreteComponent } from 'vue'\nimport type { Optional } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\n\n/**\n * Troubleshooting:\n * - If clicking on the radio doesn't do anything, check if any of its ancestor elements\n * have a @click.prevent on them anywhere.\n * - If you're not using the radio in a group, it's suggested that you set :value=\"true\",\n * so that a v-model attached to the radio will be either 'true' or 'undefined' depending on the\n * checked state\n */\n\ntype ValueType = Optional<string | true> | string[]\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst props = defineProps({\n /**\n * Input name/id. In a radio group, all radios must have the same name and different values.\n */\n name: {\n type: String,\n required: true\n },\n /**\n * Whether the input is disabled\n */\n disabled: {\n type: Boolean,\n default: false\n },\n /**\n * Set label text\n */\n label: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Help text\n */\n description: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Whether to inline the help description\n */\n inlineDescription: {\n type: Boolean,\n default: false\n },\n /**\n * Optional Icon\n */\n icon: {\n type: Object as PropType<ConcreteComponent>,\n default: undefined\n },\n /**\n * vee-validate validation rules\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<ValueType>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Radio group's value\n */\n modelValue: {\n type: [String, Boolean] as PropType<ValueType | false>,\n default: undefined\n },\n /**\n * Radio's own value. If it is checked, modelValue will include this value (amongst any other checked values from the same group).\n * If not set will default to 'name' value.\n */\n value: {\n type: [String, Boolean] as PropType<Optional<string | true>>,\n default: true\n },\n /**\n * HTML ID to use, must be globally unique. If not specified, a random ID will be generated. One is necessary to properly associate the label and radio.\n */\n id: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n hideLabel: {\n type: Boolean,\n default: false\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits([\"update:modelValue\"])\n\nconst radioValue = computed(() => props.value || props.name)\n\nconst {\n checked: coreChecked,\n errorMessage,\n handleChange,\n value: coreValue\n} = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n type: 'radio',\n checkedValue: radioValue,\n initialValue: props.modelValue || undefined\n})\n\nconst title = computed(() => props.label || props.name)\n\nconst computedClasses = computed((): string => {\n return errorMessage.value ? 'border-danger-lighter' : 'border-foreground-4 '\n})\n\nconst descriptionText = computed(() => props.description || errorMessage.value)\nconst descriptionId = computed(() => `${props.name}-description`)\nconst descriptionClasses = computed((): string => {\n const classParts: string[] = ['text-xs']\n\n if (errorMessage.value) {\n classParts.push('text-danger')\n } else {\n classParts.push('text-foreground-2')\n }\n\n return classParts.join(' ')\n})\n\nconst implicitId = ref<Optional<string>>(generateRandomId('radio'))\nconst finalId = computed(() => props.id || implicitId.value)\n\nconst onChange = (e: unknown) => {\n if (props.disabled) return\n handleChange(e)\n}\n\n/**\n * Bugfix for strange issue where radio appears checked even tho it shouldnt be.\n * It's not clear why this happens, but for some reason coreValue.value shows that the radio\n * is checked, even tho props.modelValue is undefined.\n */\nonMounted(() => {\n const newModelValue = props.modelValue\n const newCoreValue = coreValue.value\n\n const shouldBeChecked = Array.isArray(newModelValue)\n ? newModelValue.includes(props.value as any)\n : newModelValue === props.value\n\n const isCoreChecked = Array.isArray(newCoreValue)\n ? newCoreValue.includes(props.value as any)\n : newCoreValue === props.value\n\n if (shouldBeChecked !== isCoreChecked) {\n handleChange(newModelValue)\n }\n})\n</script>\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, onMounted, ref, unref } from 'vue'\nimport type { Ref, ToRefs } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\nimport { isArray } from 'lodash'\n\nexport type InputColor = 'page' | 'foundation' | 'transparent'\n\n/**\n * Common setup for text input & textarea fields\n */\nexport function useTextInputCore<V extends string | string[] = string>(params: {\n props: ToRefs<{\n name: string\n help?: string\n label?: string\n showLabel?: boolean\n rules?: RuleExpression<V>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n modelValue?: V\n autoFocus?: boolean\n showClear?: boolean\n useLabelInErrors?: boolean\n hideErrorMessage?: boolean\n color?: InputColor\n }>\n emit: {\n (e: 'change', val: { event?: Event; value: V }): void\n (e: 'clear'): void\n }\n inputEl: Ref<Nullable<HTMLInputElement | HTMLTextAreaElement>>\n options?: Partial<{\n customClear: () => void\n }>\n}) {\n const { props, inputEl, emit, options } = params\n\n const { value, errorMessage: error } = useField<V>(props.name, props.rules, {\n validateOnMount: unref(props.validateOnMount),\n validateOnValueUpdate: unref(props.validateOnValueUpdate),\n initialValue: unref(props.modelValue) || undefined\n })\n\n const labelClasses = computed(() => {\n const classParts = ['block label text-foreground-2 mb-2']\n if (!unref(props.showLabel)) {\n classParts.push('sr-only')\n }\n\n return classParts.join(' ')\n })\n\n const coreInputClasses = computed(() => {\n const classParts: string[] = [\n 'focus:outline-none disabled:cursor-not-allowed disabled:bg-foundation-disabled',\n 'disabled:text-disabled-muted placeholder:text-foreground-2',\n 'rounded'\n ]\n\n return classParts.join(' ')\n })\n\n const coreClasses = computed(() => {\n const classParts = [\n 'block w-full text-foreground transition-all',\n coreInputClasses.value\n ]\n\n if (error.value) {\n classParts.push(\n 'focus:border-danger focus:ring-danger border-2 border-danger text-danger-darker'\n )\n } else {\n classParts.push('border-0 focus:ring-2 focus:ring-outline-2')\n }\n\n const color = unref(props.color)\n if (color === 'foundation') {\n classParts.push('bg-foundation shadow-sm hover:shadow')\n } else if (color === 'transparent') {\n classParts.push('bg-transparent')\n } else {\n classParts.push('bg-foundation-page')\n }\n\n return classParts.join(' ')\n })\n\n const internalHelpTipId = ref(nanoid())\n\n const title = computed(() => unref(props.label) || unref(props.name))\n const errorMessage = computed(() => {\n const base = error.value\n if (!base || !unref(props.useLabelInErrors)) return base\n return base.replace('Value', title.value)\n })\n\n const hideHelpTip = computed(\n () => errorMessage.value && unref(props.hideErrorMessage)\n )\n const helpTip = computed(() => errorMessage.value || unref(props.help))\n const hasHelpTip = computed(() => !!helpTip.value)\n const helpTipId = computed(() =>\n hasHelpTip.value ? `${unref(props.name)}-${internalHelpTipId.value}` : undefined\n )\n const helpTipClasses = computed((): string => {\n const classParts = ['mt-2 text-xs sm:text-sm']\n classParts.push(error.value ? 'text-danger' : 'text-foreground-2')\n return classParts.join(' ')\n })\n\n const focus = () => {\n inputEl.value?.focus()\n }\n\n const clear = () => {\n value.value = (isArray(value.value) ? [] : '') as V\n options?.customClear?.()\n\n emit('change', { value: value.value })\n emit('clear')\n }\n\n onMounted(() => {\n if (unref(props.autoFocus)) {\n focus()\n }\n })\n\n return {\n coreInputClasses,\n coreClasses,\n title,\n value,\n helpTipId,\n helpTipClasses,\n helpTip,\n hideHelpTip,\n errorMessage,\n clear,\n focus,\n labelClasses\n }\n}\n","<template>\n <div :class=\"[fullWidth ? 'w-full' : '']\">\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n <div class=\"relative\">\n <textarea\n :id=\"name\"\n ref=\"inputElement\"\n v-model=\"value\"\n :name=\"name\"\n :class=\"[\n coreClasses,\n iconClasses,\n textareaClasses || '',\n 'min-h-[3rem] simple-scrollbar text-sm'\n ]\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :aria-invalid=\"errorMessage ? 'true' : 'false'\"\n :aria-describedby=\"helpTipId\"\n v-bind=\"$attrs\"\n @change=\"$emit('change', { event: $event, value })\"\n @input=\"$emit('input', { event: $event, value })\"\n />\n <a\n v-if=\"showClear\"\n title=\"Clear input\"\n class=\"absolute top-2 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-if=\"errorMessage\"\n :class=\"[\n 'pointer-events-none absolute inset-y-0 right-0 flex items-start mt-2',\n showClear ? 'pr-8' : 'pr-2'\n ]\"\n >\n <ExclamationCircleIcon class=\"h-4 w-4 text-danger\" aria-hidden=\"true\" />\n </div>\n <div\n v-if=\"showRequired && !errorMessage\"\n class=\"pointer-events-none absolute inset-y-0 mt-0.5 text-4xl right-0 flex items-start text-danger opacity-50\"\n :class=\"[showClear ? 'pr-8' : 'pr-2']\"\n >\n *\n </div>\n </div>\n <p v-if=\"helpTipId\" :id=\"helpTipId\" :class=\"helpTipClasses\">\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { ExclamationCircleIcon, XMarkIcon } from '@heroicons/vue/20/solid'\nimport type { Nullable } from '@speckle/shared'\nimport type { RuleExpression } from 'vee-validate'\nimport { computed, ref, toRefs } from 'vue'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\n\nconst emit = defineEmits([\"update:modelValue\", \"change\", \"input\", \"clear\"])\n\nconst props = defineProps({\n name: null,\n showLabel: { type: Boolean },\n help: null,\n placeholder: null,\n label: null,\n disabled: { type: Boolean },\n rules: null,\n validateOnMount: { type: Boolean },\n validateOnValueUpdate: { type: Boolean },\n useLabelInErrors: { type: Boolean, default: true },\n autoFocus: { type: Boolean },\n modelValue: { default: '' },\n showClear: { type: Boolean },\n fullWidth: { type: Boolean },\n showRequired: { type: Boolean },\n color: { default: 'page' },\n textareaClasses: null\n})\n\nconst inputElement = ref(null as Nullable<HTMLTextAreaElement>)\n\nconst {\n coreClasses,\n title,\n value,\n helpTipId,\n helpTipClasses,\n helpTip,\n errorMessage,\n labelClasses,\n clear,\n focus\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl: inputElement\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['pl-2']\n\n if (props.showClear && errorMessage.value) {\n classParts.push('pr-12')\n } else if (props.showClear || errorMessage.value) {\n classParts.push('pr-8')\n }\n\n return classParts.join(' ')\n})\n\ndefineExpose({ focus })\n</script>\n","<template>\n <div :class=\"[fullWidth ? 'w-full' : '', wrapperClasses]\">\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n <div class=\"relative\">\n <div\n v-if=\"hasLeadingIcon\"\n class=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2\"\n >\n <Component\n :is=\"customIcon\"\n v-if=\"customIcon\"\n :class=\"leadingIconClasses\"\n aria-hidden=\"true\"\n />\n <EnvelopeIcon\n v-else-if=\"type === 'email'\"\n :class=\"leadingIconClasses\"\n aria-hidden=\"true\"\n />\n <KeyIcon\n v-else-if=\"type === 'password'\"\n :class=\"leadingIconClasses\"\n aria-hidden=\"true\"\n />\n </div>\n <input\n :id=\"name\"\n ref=\"inputElement\"\n v-model=\"value\"\n :type=\"type\"\n :name=\"name\"\n :class=\"[coreClasses, iconClasses, sizeClasses, inputClasses || '']\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :aria-invalid=\"errorMessage ? 'true' : 'false'\"\n :aria-describedby=\"helpTipId\"\n role=\"textbox\"\n v-bind=\"$attrs\"\n @change=\"$emit('change', { event: $event, value })\"\n @input=\"$emit('input', { event: $event, value })\"\n @focus=\"$emit('focus')\"\n @blur=\"$emit('blur')\"\n />\n <slot name=\"input-right\">\n <a\n v-if=\"showClear\"\n title=\"Clear input\"\n class=\"absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-if=\"errorMessage\"\n :class=\"[\n 'pointer-events-none absolute inset-y-0 right-0 flex items-center',\n showClear ? 'pr-8' : 'pr-2'\n ]\"\n >\n <ExclamationCircleIcon class=\"h-4 w-4 text-danger\" aria-hidden=\"true\" />\n </div>\n <div\n v-if=\"showRequired && !errorMessage\"\n class=\"pointer-events-none absolute inset-y-0 mt-3 text-4xl right-0 flex items-center text-danger opacity-50\"\n :class=\"[showClear ? 'pr-8' : 'pr-2']\"\n >\n *\n </div>\n </slot>\n </div>\n <p v-if=\"helpTipId && !hideHelpTip\" :id=\"helpTipId\" :class=\"helpTipClasses\">\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { RuleExpression } from 'vee-validate'\nimport {\n ExclamationCircleIcon,\n EnvelopeIcon,\n KeyIcon,\n XMarkIcon\n} from '@heroicons/vue/20/solid'\nimport { computed, ref, toRefs, useSlots } from 'vue'\nimport type { PropType } from 'vue'\nimport type { Nullable, Optional } from '@speckle/shared'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype InputType = 'text' | 'email' | 'password' | 'url' | 'search' | 'number' | string\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\ntype InputColor = 'page' | 'foundation' | 'transparent'\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst props = defineProps({\n /**\n * Input \"type\" value (changes behaviour & look)\n */\n type: {\n type: String as PropType<InputType>,\n default: 'text'\n },\n /**\n * Unique ID for the input (must be unique page-wide)\n */\n name: {\n type: String,\n required: true\n },\n /**\n * Whether to show label (label will always be shown to screen readers)\n */\n showLabel: {\n type: Boolean,\n required: false\n },\n /**\n * Optional help text\n */\n help: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Placeholder text\n */\n placeholder: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Set label text explicitly\n */\n label: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to disable the component, blocking it from user input\n */\n disabled: {\n type: Boolean,\n default: false\n },\n /**\n * vee-validate validation rules\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<string>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to trigger validation whenever the value changes\n */\n validateOnValueUpdate: {\n type: Boolean,\n default: false\n },\n /**\n * Will replace the generic \"Value\" text with the name of the input in error messages\n */\n useLabelInErrors: {\n type: Boolean,\n default: true\n },\n /**\n * Set a custom icon to use inside the input\n */\n customIcon: {\n type: [Object, Function] as PropType<Optional<PropAnyComponent>>,\n default: undefined\n },\n /**\n * Whether to focus on the input when component is mounted\n */\n autoFocus: {\n type: Boolean,\n default: false\n },\n modelValue: {\n type: String,\n default: ''\n },\n size: {\n type: String as PropType<InputSize>,\n default: 'base'\n },\n showClear: {\n type: Boolean,\n default: false\n },\n fullWidth: {\n type: Boolean,\n default: false\n },\n inputClasses: {\n type: String,\n default: null\n },\n hideErrorMessage: {\n type: Boolean,\n default: false\n },\n wrapperClasses: {\n type: String,\n default: () => ''\n },\n color: {\n type: String as PropType<InputColor>,\n default: 'page'\n }\n})\n\nconst emit = defineEmits([\"update:modelValue\", \"change\", \"input\", \"clear\", \"focus\", \"blur\"])\n\nconst slots = useSlots()\n\nconst inputElement = ref(null as Nullable<HTMLInputElement>)\n\nconst {\n coreClasses,\n title,\n value,\n helpTipId,\n helpTipClasses,\n helpTip,\n hideHelpTip,\n errorMessage,\n clear,\n focus,\n labelClasses\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl: inputElement\n})\n\nconst leadingIconClasses = computed(() => {\n const classParts: string[] = ['h-5 w-5']\n\n if (errorMessage.value) {\n classParts.push('text-danger')\n } else {\n classParts.push('text-foreground-2')\n }\n\n return classParts.join(' ')\n})\n\nconst hasLeadingIcon = computed(\n () => ['email', 'password'].includes(props.type) || props.customIcon\n)\n\nconst iconClasses = computed((): string => {\n const classParts: string[] = []\n\n if (hasLeadingIcon.value) {\n classParts.push('pl-8')\n } else {\n classParts.push('pl-2')\n }\n\n if (!slots['input-right']) {\n if (errorMessage.value || props.showClear) {\n if (errorMessage.value && props.showClear) {\n classParts.push('pr-12')\n } else {\n classParts.push('pr-8')\n }\n }\n }\n\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed((): string => {\n switch (props.size) {\n case 'sm':\n return 'h-6 text-sm'\n case 'lg':\n return 'h-10'\n case 'xl':\n return 'h-14'\n case 'base':\n default:\n return 'h-8 text-sm'\n }\n})\n\ndefineExpose({ focus })\n</script>\n","import { isString, isUndefined } from 'lodash'\nimport type { GenericValidateFunction } from 'vee-validate'\nimport { isNullOrUndefined } from '@speckle/shared'\n\nexport const VALID_HTTP_URL = /^https?:\\/\\//\nexport const VALID_EMAIL = /^[\\w-_.+]+@[\\w-_.+]+$/\n\n/**\n * Note about new validators:\n * Make sure you use the word \"Value\" to refer to the value being validated in all error messages, cause the dynamic string replace\n * that replaces that part with the actual field name works based on that\n */\n\n/**\n * E-mail validation rule (not perfect, but e-mails should be validated by sending out confirmation e-mails anyway)\n */\nexport const isEmail: GenericValidateFunction<string> = (val) =>\n (val || '').match(VALID_EMAIL) ? true : 'Value should be a valid e-mail address'\n\nexport const isOneOrMultipleEmails: GenericValidateFunction<string> = (val) => {\n const emails = (val || '').split(',').map((i) => i.trim())\n const valid = emails.every((e) => e.match(VALID_EMAIL))\n return valid || 'Value should be one or multiple comma-delimited e-mail addresses'\n}\n\nexport const isRequired: GenericValidateFunction<unknown> = (val) => {\n if (isString(val)) {\n val = val.trim()\n }\n\n return val ? true : 'Value is required'\n}\n\nexport const isSameAs: (\n otherFieldName: string,\n otherFieldDisplayName?: string\n) => GenericValidateFunction<unknown> =\n (otherFieldName, otherFieldDisplayName) => (val, meta) => {\n return val === meta.form[otherFieldName]\n ? true\n : `Value must be the same as in field '${\n otherFieldDisplayName || otherFieldName\n }'`\n }\n\nexport const isStringOfLength =\n (params: {\n minLength?: number\n maxLength?: number\n }): GenericValidateFunction<string> =>\n (val) => {\n const { minLength, maxLength } = params\n val = isNullOrUndefined(val) ? '' : val\n\n if (!isString(val)) return 'Value should be a text string'\n if (!isUndefined(minLength) && val.length < minLength)\n return `Value needs to be at least ${minLength} characters long`\n if (!isUndefined(maxLength) && val.length > maxLength)\n return `Value needs to be no more than ${maxLength} characters long`\n return true\n }\n\nexport const stringContains =\n (params: {\n match: string | RegExp\n message: string\n }): GenericValidateFunction<string> =>\n (val) => {\n const { match, message } = params\n\n if (!isString(val)) return 'Value should be a text string'\n if (!match) return true\n\n if (isString(match)) {\n return val.includes(match) ? true : message\n } else {\n return match.test(val) ? true : message\n }\n }\n\nexport const isUrl: GenericValidateFunction<string> = (value) => {\n if (VALID_HTTP_URL.test(value)) {\n return true\n }\n return 'Value is not a valid URL'\n}\n\nexport const isItemSelected: GenericValidateFunction<unknown[]> = (val) => {\n if (Array.isArray(val) && val.length > 0) {\n return true\n }\n return 'Value should have at least a single item selected'\n}\n","import type { Nullable, Optional } from '@speckle/shared'\nimport { useMutationObserver, useResizeObserver } from '@vueuse/core'\nimport { isUndefined } from 'lodash'\nimport { ref } from 'vue'\nimport type { Ref, ComputedRef } from 'vue'\n\n/**\n * Use this to calculate the number of hidden elements (e.g. user avatars) in a wrapping flex row that\n * is styled to only show the first row. For example, there are 12 users total, there's only space for 5,\n * and this composable will calculate the number of hidden ones to use for the \"+X\" label (+7 in the example)\n *\n * Note: The \"hidden\" items must wrap into another line, because we use their offset from the top of the parent\n * to check if they're hidden (compared to items in the 1st row)\n */\nexport function useWrappingContainerHiddenCount(params: {\n /**\n * Element to watch for any changes\n */\n elementToWatchForChanges: Ref<Nullable<HTMLElement>>\n /**\n * The element that actually contains the potentially visible/hidden items as direct children\n */\n itemContainer: Ref<Nullable<HTMLElement>>\n\n /**\n * Allows you to pause calculations conditionally\n */\n skipCalculation?: ComputedRef<boolean>\n\n /**\n * If true, will track resizing of 'elementToWatchForChanges'.\n * Default: false\n */\n trackResize?: boolean\n\n /**\n * If true, will track descendants being added/removed to 'elementToWatchForChanges'.\n * Default: true\n */\n trackMutations?: boolean\n}) {\n const {\n skipCalculation,\n elementToWatchForChanges,\n itemContainer,\n trackResize = false,\n trackMutations = true\n } = params || {}\n\n /**\n * Dynamically updated to show the number of items currently not visible in the container\n */\n const hiddenItemCount = ref(0)\n\n const recalculate = () => {\n const target = itemContainer.value\n if (skipCalculation?.value || !target) return\n\n const avatarElements = target.children\n\n /**\n * Comparing offset from parent to between all avatars to see when they break off into another line\n * and become invisible\n */\n let visibleCount = 0\n let totalCount = 0\n let firstElOffsetTop = undefined as Optional<number>\n for (const avatarEl of avatarElements) {\n const offsetTop = (avatarEl as HTMLElement).offsetTop\n if (isUndefined(firstElOffsetTop)) {\n firstElOffsetTop = offsetTop\n visibleCount += 1\n } else {\n if (offsetTop === firstElOffsetTop) {\n visibleCount += 1\n }\n }\n\n totalCount += 1\n }\n\n hiddenItemCount.value = totalCount - visibleCount\n }\n\n if (trackResize) {\n useResizeObserver(elementToWatchForChanges, recalculate)\n }\n\n if (trackMutations) {\n useMutationObserver(elementToWatchForChanges, recalculate, {\n childList: true,\n subtree: true\n })\n }\n\n return {\n hiddenItemCount\n }\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\nimport { isArray } from 'lodash'\nimport { computed, ref } from 'vue'\nimport type { Ref, ToRefs } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport { useWrappingContainerHiddenCount } from '~~/src/composables/layout/resize'\n\ntype GenericSelectValueType<T> = T | T[] | undefined\n\n/**\n * Common setup for FormSelectBase wrapping selector components\n */\nexport function useFormSelectChildInternals<T>(params: {\n props: ToRefs<{\n modelValue?: GenericSelectValueType<T>\n multiple?: boolean\n }>\n emit: {\n (e: 'update:modelValue', val: GenericSelectValueType<T>): void\n }\n /**\n * @see {useWrappingContainerHiddenCount()}\n */\n dynamicVisibility?: {\n elementToWatchForChanges: Ref<Nullable<HTMLElement>>\n itemContainer: Ref<Nullable<HTMLElement>>\n }\n}) {\n const { props, emit, dynamicVisibility } = params\n\n let hiddenItemCount: Ref<number>\n if (dynamicVisibility) {\n const { elementToWatchForChanges, itemContainer } = dynamicVisibility\n const hiddenCountData = useWrappingContainerHiddenCount({\n skipCalculation: computed(() => !props.multiple?.value),\n elementToWatchForChanges,\n itemContainer\n })\n hiddenItemCount = hiddenCountData.hiddenItemCount\n } else {\n hiddenItemCount = ref(0)\n }\n\n /**\n * Use this to get or set the v-model value of the select input in a proper way\n */\n const selectedValue = computed({\n get: (): GenericSelectValueType<T> => {\n const currentValue = props.modelValue?.value\n if (props.multiple?.value) {\n return isArray(currentValue) ? currentValue : []\n } else {\n return isArray(currentValue) ? undefined : currentValue\n }\n },\n set: (newVal: GenericSelectValueType<T>) => {\n if (props.multiple?.value && !isArray(newVal)) {\n console.warn('Attempting to set non-array value in selector w/ multiple=true')\n return\n } else if (!props.multiple?.value && isArray(newVal)) {\n console.warn('Attempting to set array value in selector w/ multiple=false')\n return\n }\n\n emit('update:modelValue', props.multiple?.value ? newVal || [] : newVal)\n }\n })\n\n const isArrayValue = (v: GenericSelectValueType<T>): v is T[] => isArray(v)\n const isMultiItemArrayValue = (v: GenericSelectValueType<T>): v is T[] =>\n isArray(v) && v.length > 1\n const firstItem = (v: NonNullable<GenericSelectValueType<T>>): T =>\n isArrayValue(v) ? v[0] : v\n\n return {\n selectedValue,\n hiddenSelectedItemCount: hiddenItemCount,\n isArrayValue,\n isMultiItemArrayValue,\n firstItem\n }\n}\n","<template>\n <div>\n <Listbox\n :key=\"forceUpdateKey\"\n v-model=\"wrappedValue\"\n :name=\"name\"\n :multiple=\"multiple\"\n :by=\"by\"\n :disabled=\"isDisabled\"\n as=\"div\"\n >\n <ListboxLabel\n class=\"block label text-foreground-2 mb-2\"\n :class=\"{ 'sr-only': !showLabel }\"\n >\n {{ label }}\n </ListboxLabel>\n <div :class=\"buttonsWrapperClasses\">\n <!-- <div class=\"relative flex\"> -->\n <ListboxButton ref=\"listboxButton\" v-slot=\"{ open }\" :class=\"buttonClasses\">\n <div class=\"flex items-center justify-between w-full\">\n <div class=\"block truncate grow text-left text-xs sm:text-sm\">\n <template\n v-if=\"!wrappedValue || (isArray(wrappedValue) && !wrappedValue.length)\"\n >\n <slot name=\"nothing-selected\">\n {{ placeholder ? placeholder : label }}\n </slot>\n </template>\n <template v-else>\n <slot name=\"something-selected\" :value=\"wrappedValue\">\n {{ simpleDisplayText(wrappedValue) }}\n </slot>\n </template>\n </div>\n <div class=\"pointer-events-none shrink-0 ml-1 flex items-center space-x-2\">\n <ExclamationCircleIcon\n v-if=\"errorMessage\"\n class=\"h-4 w-4 text-danger\"\n aria-hidden=\"true\"\n />\n <div\n v-else-if=\"showRequired\"\n class=\"text-4xl text-danger opacity-50 h-4 w-4 leading-6\"\n >\n *\n </div>\n <ChevronUpIcon\n v-if=\"open\"\n class=\"h-4 w-4 text-foreground\"\n aria-hidden=\"true\"\n />\n <ChevronDownIcon\n v-else\n class=\"h-4 w-4 text-foreground\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n </ListboxButton>\n <!-- </div> -->\n <!-- Clear Button -->\n <button\n v-if=\"renderClearButton\"\n v-tippy=\"'Clear'\"\n :class=\"clearButtonClasses\"\n :disabled=\"disabled\"\n @click=\"clearValue()\"\n >\n <XMarkIcon class=\"w-3 h-3\" />\n </button>\n <Transition\n v-if=\"isMounted\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"opacity-100\"\n leave-to-class=\"opacity-0\"\n >\n <Teleport to=\"body\" :disabled=\"!mountMenuOnBody\">\n <ListboxOptions\n ref=\"menuEl\"\n :class=\"listboxOptionsClasses\"\n :style=\"listboxOptionsStyle\"\n @focus=\"searchInput?.focus()\"\n >\n <label v-if=\"hasSearch\" class=\"flex flex-col mx-1 mb-1\">\n <span class=\"sr-only label text-foreground\">Search</span>\n <div class=\"relative\">\n <div\n class=\"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2\"\n >\n <MagnifyingGlassIcon class=\"h-5 w-5 text-foreground\" />\n </div>\n <input\n ref=\"searchInput\"\n v-model=\"searchValue\"\n type=\"text\"\n class=\"pl-9 w-full border-0 bg-foundation-page rounded placeholder:font-normal normal placeholder:text-foreground-2 focus:outline-none focus:ring-1 focus:border-outline-1 focus:ring-outline-1\"\n :placeholder=\"searchPlaceholder\"\n @keydown.stop\n />\n </div>\n </label>\n <div\n class=\"overflow-auto simple-scrollbar\"\n :class=\"[hasSearch ? 'max-h-52' : 'max-h-40']\"\n >\n <div v-if=\"isAsyncSearchMode && isAsyncLoading\" class=\"px-1\">\n <CommonLoadingBar :loading=\"true\" />\n </div>\n <div v-else-if=\"isAsyncSearchMode && !currentItems.length\">\n <slot name=\"nothing-found\">\n <div class=\"text-foreground-2 text-center\">Nothing found 🤷‍♂️</div>\n </slot>\n </div>\n <template v-if=\"!isAsyncSearchMode || !isAsyncLoading\">\n <ListboxOption\n v-for=\"item in finalItems\"\n :key=\"itemKey(item)\"\n v-slot=\"{\n active,\n selected\n }: {\n active: boolean,\n selected: boolean\n }\"\n :value=\"item\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n <li\n :class=\"\n listboxOptionClasses({\n active,\n disabled: disabledItemPredicate?.(item) || false\n })\n \"\n >\n <span :class=\"['block truncate']\">\n <slot\n name=\"option\"\n :item=\"item\"\n :active=\"active\"\n :selected=\"selected\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n {{ simpleDisplayText(item) }}\n </slot>\n </span>\n\n <span\n v-if=\"!hideCheckmarks && selected\"\n :class=\"[\n active ? 'text-primary' : 'text-foreground',\n 'absolute inset-y-0 right-0 flex items-center pr-4'\n ]\"\n >\n <CheckIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </span>\n </li>\n </ListboxOption>\n </template>\n </div>\n </ListboxOptions>\n </Teleport>\n </Transition>\n </div>\n </Listbox>\n <p\n v-if=\"helpTipId\"\n :id=\"helpTipId\"\n class=\"mt-2 text-xs sm:text-sm\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script\n setup\n lang=\"ts\"\n generic=\"SingleItem extends Record<string, unknown> | string | number\"\n>\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport {\n Listbox,\n ListboxButton,\n ListboxOption,\n ListboxOptions,\n ListboxLabel\n} from '@headlessui/vue'\nimport {\n ChevronDownIcon,\n CheckIcon,\n ChevronUpIcon,\n MagnifyingGlassIcon,\n XMarkIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/24/solid'\nimport { debounce, isArray, isObjectLike } from 'lodash'\nimport type { CSSProperties, PropType, Ref } from 'vue'\nimport { computed, onMounted, ref, unref, watch } from 'vue'\nimport type { MaybeAsync, Nullable, Optional } from '@speckle/shared'\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\nimport { nanoid } from 'nanoid'\nimport CommonLoadingBar from '~~/src/components/common/loading/Bar.vue'\nimport { directive as vTippy } from 'vue-tippy'\nimport { useElementBounding, useMounted, useIntersectionObserver } from '@vueuse/core'\n\ntype ButtonStyle = 'base' | 'simple' | 'tinted'\ntype ValueType = SingleItem | SingleItem[] | undefined\n\nconst isObjectLikeType = (v: unknown): v is Record<string, unknown> => isObjectLike(v)\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n multiple: {\n type: Boolean,\n default: false\n },\n items: {\n type: Array as PropType<SingleItem[]>,\n default: () => []\n },\n modelValue: {\n type: [Object, Array, String] as PropType<ValueType>,\n default: undefined\n },\n /**\n * Whether to enable the search bar. You must also set one of the following:\n * * filterPredicate - to allow filtering passed in `items` based on search bar\n * * getSearchResults - to allow asynchronously loading items from server (props.items no longer required in this case,\n * but can be used to prefill initial values)\n */\n search: {\n type: Boolean,\n default: false\n },\n /**\n * If search=true and this is set, you can use this to filter passed in items based on whatever\n * the user enters in the search bar\n */\n filterPredicate: {\n type: Function as PropType<\n Optional<(item: SingleItem, searchString: string) => boolean>\n >,\n default: undefined\n },\n /**\n * Set this to disable certain items in the list\n */\n disabledItemPredicate: {\n type: Function as PropType<Optional<(item: SingleItem) => boolean>>,\n default: undefined\n },\n /**\n * If search=true and this is set, you can use this to load data asynchronously depending\n * on the search query\n */\n getSearchResults: {\n type: Function as PropType<\n Optional<(searchString: string) => MaybeAsync<SingleItem[]>>\n >,\n default: undefined\n },\n searchPlaceholder: {\n type: String,\n default: 'Search'\n },\n /**\n * Label is required at the very least for screen-readers\n */\n label: {\n type: String,\n required: true\n },\n /**\n * Optional text that replaces the label as the placeholder when set.\n */\n placeholder: {\n type: String\n },\n /**\n * Whether to show the label visually\n */\n showLabel: {\n type: Boolean,\n default: false\n },\n name: {\n type: String,\n required: true\n },\n /**\n * Objects will be compared by the values in the specified prop\n */\n by: {\n type: String,\n required: false\n },\n disabled: {\n type: Boolean as PropType<Optional<boolean>>,\n default: false\n },\n buttonStyle: {\n type: String as PropType<Optional<ButtonStyle>>,\n default: 'base'\n },\n hideCheckmarks: {\n type: Boolean as PropType<Optional<boolean>>,\n default: false\n },\n allowUnset: {\n type: Boolean as PropType<Optional<boolean>>,\n default: true\n },\n clearable: {\n type: Boolean,\n default: false\n },\n /**\n * Validation stuff\n */\n rules: {\n type: [String, Object, Function, Array] as PropType<RuleExpression<ValueType>>,\n default: undefined\n },\n /**\n * vee-validate validation() on component mount\n */\n validateOnMount: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to trigger validation whenever the value changes\n */\n validateOnValueUpdate: {\n type: Boolean,\n default: false\n },\n /**\n * Will replace the generic \"Value\" text with the name of the input in error messages\n */\n useLabelInErrors: {\n type: Boolean,\n default: true\n },\n /**\n * Optional help text\n */\n help: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n fixedHeight: {\n type: Boolean,\n default: false\n },\n /**\n * By default component holds its own internal value state so that even if you don't have it tied up to a real `modelValue` ref somewhere\n * it knows its internal state and can report it on form submits.\n *\n * If you set this to true, its only going to rely on `modelValue` as its primary source of truth so that you can reject updates etc.\n */\n fullyControlValue: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to show the red \"required\" asterisk\n */\n showRequired: {\n type: Boolean,\n default: false\n },\n /**\n * Whether to mount the menu on the body instead of inside the component. Useful when select box is mounted within\n * dialog windows and the menu causes unnecessary overflow.\n */\n mountMenuOnBody: {\n type: Boolean,\n default: false\n }\n})\n\nconst { value, errorMessage: error } = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n initialValue: props.modelValue as ValueType\n})\n\nconst isMounted = useMounted()\n\nconst searchInput = ref(null as Nullable<HTMLInputElement>)\nconst menuEl = ref(null as Nullable<{ el: Nullable<HTMLElement> }>)\nconst listboxButton = ref(null as Nullable<{ el: Nullable<HTMLButtonElement> }>)\nconst searchValue = ref('')\nconst currentItems = ref([]) as Ref<SingleItem[]>\nconst isAsyncLoading = ref(false)\nconst forceUpdateKey = ref(1)\nconst internalHelpTipId = ref(nanoid())\n\nconst listboxButtonBounding = useElementBounding(\n computed(() => listboxButton.value?.el),\n { windowResize: true, windowScroll: true, immediate: true }\n)\n\nuseIntersectionObserver(\n computed(() => menuEl.value?.el),\n ([{ isIntersecting }]) => {\n if (isIntersecting && props.mountMenuOnBody) {\n listboxButtonBounding.update()\n }\n }\n)\n\nconst title = computed(() => unref(props.label) || unref(props.name))\nconst errorMessage = computed(() => {\n const base = error.value\n if (!base || !unref(props.useLabelInErrors)) return base\n return base.replace('Value', title.value)\n})\nconst helpTip = computed(() => errorMessage.value || unref(props.help))\nconst hasHelpTip = computed(() => !!helpTip.value)\nconst helpTipId = computed(() =>\n hasHelpTip.value ? `${unref(props.name)}-${internalHelpTipId.value}` : undefined\n)\nconst helpTipClasses = computed((): string =>\n error.value ? 'text-danger' : 'text-foreground-2'\n)\n\nconst renderClearButton = computed(\n () => props.buttonStyle !== 'simple' && props.clearable && !props.disabled\n)\n\nconst buttonsWrapperClasses = computed(() => {\n const classParts: string[] = ['relative flex group']\n\n if (error.value) {\n classParts.push('hover:shadow rounded-md')\n classParts.push('text-danger-darker focus:border-danger focus:ring-danger')\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('outline outline-2 outline-danger')\n }\n } else if (props.buttonStyle !== 'simple') {\n classParts.push('hover:shadow rounded-md')\n classParts.push('outline outline-2 outline-primary-muted')\n }\n\n if (props.fixedHeight) {\n classParts.push('h-8')\n }\n\n return classParts.join(' ')\n})\n\nconst commonButtonClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.buttonStyle !== 'simple') {\n // classParts.push('group-hover:shadow')\n // classParts.push('outline outline-2 outline-primary-muted ')\n classParts.push(\n isDisabled.value ? 'bg-foundation-disabled text-foreground-disabled' : ''\n )\n }\n\n if (isDisabled.value) classParts.push('cursor-not-allowed')\n\n return classParts.join(' ')\n})\n\nconst clearButtonClasses = computed(() => {\n const classParts = [\n 'relative z-[1]',\n 'flex items-center justify-center text-center shrink-0',\n 'rounded-r-md overflow-hidden transition-all',\n 'text-foreground',\n hasValueSelected.value ? `w-6 ${commonButtonClasses.value}` : 'w-0'\n ]\n\n if (!isDisabled.value) {\n classParts.push(\n 'hover:bg-primary hover:text-foreground-on-primary dark:text-foreground-on-primary'\n )\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-outline-3')\n } else {\n classParts.push('bg-primary-muted')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst buttonClasses = computed(() => {\n const classParts = [\n 'relative z-[2]',\n 'normal rounded-md cursor-pointer transition truncate flex-1',\n 'flex items-center',\n commonButtonClasses.value\n ]\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('py-2 px-3')\n\n if (!isDisabled.value) {\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-foundation-page text-foreground')\n } else {\n classParts.push('bg-foundation text-foreground')\n }\n }\n }\n\n if (renderClearButton.value && hasValueSelected.value) {\n classParts.push('rounded-r-none')\n }\n\n return classParts.join(' ')\n})\n\nconst hasSearch = computed(\n () => !!(props.search && (props.filterPredicate || props.getSearchResults))\n)\nconst isAsyncSearchMode = computed(() => hasSearch.value && props.getSearchResults)\nconst isDisabled = computed(\n () => props.disabled || (!props.items.length && !isAsyncSearchMode.value)\n)\n\nconst wrappedValue = computed({\n get: () => {\n const currentValue = value.value\n if (props.multiple) {\n return isArray(currentValue) ? currentValue : []\n } else {\n return isArray(currentValue) ? undefined : currentValue\n }\n },\n set: (newVal) => {\n if (props.multiple && !isArray(newVal)) {\n console.warn('Attempting to set non-array value in selector w/ multiple=true')\n return\n } else if (!props.multiple && isArray(newVal)) {\n console.warn('Attempting to set array value in selector w/ multiple=false')\n return\n }\n\n let finalValue: typeof value.value\n if (props.multiple) {\n finalValue = newVal || []\n } else {\n const currentVal = value.value\n const isUnset =\n props.allowUnset &&\n currentVal &&\n newVal &&\n itemKey(currentVal as SingleItem) === itemKey(newVal as SingleItem)\n finalValue = isUnset ? undefined : newVal\n }\n\n if (props.fullyControlValue) {\n // Not setting value.value, cause then we don't give a chance for the parent\n // component to reject the update\n emit('update:modelValue', finalValue)\n } else {\n value.value = finalValue\n }\n\n // hacky, but there's no other way to force ListBox to re-read the modelValue prop which\n // we need in case the update was rejected and ListBox still thinks the value is the one\n // that was clicked on\n forceUpdateKey.value += 1\n }\n})\n\nconst hasValueSelected = computed(() => {\n if (props.multiple && isArray(wrappedValue.value))\n return wrappedValue.value.length !== 0\n else return !!wrappedValue.value\n})\n\nconst clearValue = () => {\n if (props.multiple) wrappedValue.value = []\n else wrappedValue.value = undefined\n}\n\nconst finalItems = computed(() => {\n const searchVal = searchValue.value\n if (!hasSearch.value || !searchVal?.length) return currentItems.value\n\n if (props.filterPredicate) {\n return currentItems.value.filter(\n (i) => props.filterPredicate?.(i, searchVal) || false\n )\n }\n\n return currentItems.value\n})\n\nconst listboxOptionsClasses = computed(() => {\n const classParts = [\n 'rounded-md bg-foundation-2 py-1 label label--light outline outline-2 outline-primary-muted focus:outline-none shadow mt-1 '\n ]\n\n if (props.mountMenuOnBody) {\n classParts.push('fixed z-50')\n } else {\n classParts.push('absolute top-[100%] w-full z-10')\n }\n\n return classParts.join(' ')\n})\n\nconst listboxOptionsStyle = computed(() => {\n const style: CSSProperties = {}\n\n if (props.mountMenuOnBody) {\n const top = listboxButtonBounding.top.value\n const left = listboxButtonBounding.left.value\n const width = listboxButtonBounding.width.value\n const height = listboxButtonBounding.height.value\n\n style.top = `${top + height}px`\n style.left = `${left}px`\n style.width = `${width}px`\n }\n\n return style\n})\n\nconst simpleDisplayText = (v: ValueType) => JSON.stringify(v)\nconst itemKey = (v: SingleItem): string | number => {\n if (isObjectLikeType(v)) {\n return v[props.by || 'id'] as string\n } else {\n return v\n }\n}\n\nconst triggerSearch = async () => {\n if (!isAsyncSearchMode.value || !props.getSearchResults) return\n\n isAsyncLoading.value = true\n try {\n currentItems.value = await props.getSearchResults(searchValue.value)\n } finally {\n isAsyncLoading.value = false\n }\n}\nconst debouncedSearch = debounce(triggerSearch, 1000)\n\nconst listboxOptionClasses = (params: { active: boolean; disabled: boolean }) => {\n const { active, disabled } = params || {}\n const { hideCheckmarks } = props\n\n const classParts = [\n 'relative transition cursor-pointer select-none py-1.5 pl-3',\n !hideCheckmarks ? 'pr-9' : ''\n ]\n\n if (disabled) {\n classParts.push('opacity-50 cursor-not-allowed')\n } else {\n classParts.push(active ? 'text-primary' : 'text-foreground')\n }\n\n return classParts.join(' ')\n}\n\nwatch(\n () => props.items,\n (newItems) => {\n currentItems.value = newItems.slice()\n },\n { immediate: true }\n)\n\nwatch(searchValue, () => {\n if (!isAsyncSearchMode.value) return\n debouncedSearch()\n})\n\nonMounted(() => {\n if (isAsyncSearchMode.value && !props.items.length) {\n triggerSearch()\n }\n})\n\ndefineExpose({ triggerSearch })\n</script>\n","<template>\n <FormSelectBase\n v-model=\"selectedValue\"\n :multiple=\"multiple\"\n :items=\"items ?? SourceApps\"\n :search=\"search\"\n :search-placeholder=\"searchPlaceholder\"\n :label=\"label\"\n :show-label=\"showLabel\"\n :name=\"name || 'sourceApps'\"\n :filter-predicate=\"searchFilterPredicate\"\n :clearable=\"clearable\"\n :help=\"help\"\n by=\"name\"\n >\n <template #nothing-selected>\n <template v-if=\"selectorPlaceholder\">\n {{ selectorPlaceholder }}\n </template>\n <template v-else>\n {{ multiple ? 'Select apps' : 'Select an app' }}\n </template>\n </template>\n <template #something-selected=\"{ value }\">\n <template v-if=\"isMultiItemArrayValue(value)\">\n <div ref=\"elementToWatchForChanges\" class=\"flex items-center space-x-0.5 h-5\">\n <div\n ref=\"itemContainer\"\n class=\"flex flex-wrap overflow-hidden space-x-0.5 h-5\"\n >\n <SourceAppBadge v-for=\"item in value\" :key=\"item.name\" :source-app=\"item\" />\n </div>\n <div v-if=\"hiddenSelectedItemCount > 0\" class=\"text-foreground-2 normal\">\n +{{ hiddenSelectedItemCount }}\n </div>\n </div>\n </template>\n <template v-else>\n <div class=\"flex items-center\">\n <div\n class=\"h-2 w-2 rounded-full mr-2\"\n :style=\"{ backgroundColor: firstItem(value).bgColor }\"\n />\n <span class=\"truncate\">{{ firstItem(value).name }}</span>\n </div>\n </template>\n </template>\n <template #option=\"{ item }\">\n <div class=\"flex items-center\">\n <div\n class=\"h-2 w-2 rounded-full mr-2\"\n :style=\"{ backgroundColor: item.bgColor }\"\n />\n <span class=\"truncate\">{{ item.name }}</span>\n </div>\n </template>\n </FormSelectBase>\n</template>\n<script setup lang=\"ts\">\nimport type { Nullable, Optional, SourceAppDefinition } from '@speckle/shared'\nimport { SourceApps } from '@speckle/shared'\nimport { ref, toRefs } from 'vue'\nimport type { PropType } from 'vue'\nimport { useFormSelectChildInternals } from '~~/src/composables/form/select'\nimport FormSelectBase from '~~/src/components/form/select/Base.vue'\nimport SourceAppBadge from '~~/src/components/SourceAppBadge.vue'\n\ntype ValueType = SourceAppDefinition | SourceAppDefinition[] | undefined\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n /**\n * Whether to allow selecting multiple source apps\n */\n multiple: {\n type: Boolean,\n default: false\n },\n modelValue: {\n type: [Object, Array] as PropType<ValueType>,\n default: undefined\n },\n /**\n * Whether to allow filtering source apps through a search box\n */\n search: {\n type: Boolean,\n default: false\n },\n /**\n * Search placeholder text\n */\n searchPlaceholder: {\n type: String,\n default: 'Search apps'\n },\n selectorPlaceholder: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Label is required at the very least for screen-readers\n */\n label: {\n type: String,\n required: true\n },\n /**\n * Whether to show the label visually\n */\n showLabel: {\n type: Boolean,\n default: false\n },\n name: {\n type: String as PropType<Optional<string>>,\n default: undefined\n },\n /**\n * Control source apps to show. If left undefined, will show all available options.\n */\n items: {\n type: Array as PropType<Optional<SourceAppDefinition[]>>,\n default: undefined\n },\n clearable: {\n type: Boolean\n },\n help: {\n type: String\n }\n})\n\nconst elementToWatchForChanges = ref(null as Nullable<HTMLElement>)\nconst itemContainer = ref(null as Nullable<HTMLElement>)\n\nconst { selectedValue, hiddenSelectedItemCount, isMultiItemArrayValue, firstItem } =\n useFormSelectChildInternals<SourceAppDefinition>({\n props: toRefs(props),\n emit,\n dynamicVisibility: { elementToWatchForChanges, itemContainer }\n })\n\nconst searchFilterPredicate = (i: SourceAppDefinition, search: string) =>\n i.name.toLocaleLowerCase().includes(search.toLocaleLowerCase())\n</script>\n","<template>\n <FormSelectBase\n v-model=\"selectedValue\"\n :multiple=\"multiple\"\n :items=\"items\"\n :label=\"label\"\n :name=\"name\"\n :help=\"help\"\n :rules=\"rules\"\n :by=\"by\"\n >\n <template #something-selected=\"{ value }\">\n <ul class=\"flex flex-wrap gap-1.5 text-xs\">\n <li v-for=\"item in isArrayValue(value) ? value : [value]\" :key=\"item[by]\">\n <CommonBadge\n size=\"lg\"\n :clickable-icon=\"true\"\n :icon-left=\"XMarkIcon\"\n @click-icon.stop=\"deselectItem(item)\"\n >\n {{ item.text }}\n </CommonBadge>\n </li>\n </ul>\n </template>\n <template #option=\"{ item }\">\n {{ item.text }}\n </template>\n </FormSelectBase>\n</template>\n\n<script setup lang=\"ts\">\n// Vue components don't support generic props, so having to rely on any\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n\nimport { toRefs } from 'vue'\nimport FormSelectBase from '~~/src/components/form/select/Base.vue'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\nimport { useFormSelectChildInternals } from '~~/src/composables/form/select'\nimport { XMarkIcon } from '@heroicons/vue/24/solid'\n\ntype SingleItem = any\n\nconst emit = defineEmits([\"update:modelValue\"])\n\nconst props = defineProps({\n items: null,\n label: null,\n name: null,\n help: null,\n modelValue: null,\n multiple: { type: Boolean },\n rules: null,\n by: null\n})\n\nconst { selectedValue, isArrayValue } = useFormSelectChildInternals<SingleItem>({\n props: toRefs(props),\n emit\n})\n\nconst deselectItem = (item: SingleItem) => {\n if (isArrayValue(selectedValue.value)) {\n selectedValue.value = selectedValue.value.filter((i) => i.id !== item.id)\n } else {\n selectedValue.value = undefined\n }\n}\n</script>\n","<template>\n <div class=\"flex items-center\">\n <HeadlessSwitch\n v-model=\"enabled\"\n class=\"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary\"\n :class=\"{ 'bg-primary': enabled, 'bg-primary-muted': !enabled }\"\n >\n <div class=\"absolute inset-0 flex items-center gap-2 px-1 text-white\">\n <CheckIcon\n class=\"h-5 w-5 drop-shadow-md\"\n :class=\"icons ? 'opacity-100' : 'opacity-0'\"\n />\n <XMarkIcon\n class=\"h-5 w-5 drop-shadow-md\"\n :class=\"icons ? 'opacity-100' : 'opacity-0'\"\n />\n </div>\n <span\n class=\"scale-95 pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200\"\n :class=\"{ 'translate-x-5': enabled, 'translate-x-0': !enabled }\"\n ></span>\n </HeadlessSwitch>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Switch as HeadlessSwitch } from '@headlessui/vue'\nimport { CheckIcon, XMarkIcon } from '@heroicons/vue/24/solid'\n\ndefineProps({\n icons: { type: Boolean }\n})\n\nconst enabled = defineModel<boolean>()\n</script>\n","<template>\n <div class=\"relative group bg-foundation-page p-2 rounded-lg pr-12\">\n <div\n v-if=\"isMultiline\"\n class=\"relative z-10 text-xs sm:text-sm text-foreground font-mono break-all p-2 pl-3 max-h-[4.8rem] simple-scrollbar overflow-y-auto\"\n @keypress=\"keyboardClick(selectAllText)\"\n >\n {{ value }}\n </div>\n <FormTextInput\n v-else\n color=\"transparent\"\n name=\"contentInput\"\n readonly\n :model-value=\"value\"\n class=\"relative z-10 text-sm text-foreground font-mono\"\n />\n <div class=\"absolute inset-0 right-2 flex justify-end items-center\">\n <FormButton\n color=\"invert\"\n size=\"sm\"\n :icon-left=\"copied ? ClipboardDocumentCheckIcon : ClipboardDocumentIcon\"\n hide-text\n @click=\"handleCopy\"\n ></FormButton>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useClipboard } from '@vueuse/core'\nimport {\n ClipboardDocumentIcon,\n ClipboardDocumentCheckIcon\n} from '@heroicons/vue/24/outline'\nimport { FormTextInput, FormButton } from '~~/src/lib'\nimport { ref } from 'vue'\nimport { keyboardClick } from '~~/src/helpers/global/accessibility'\n\ntype Props = {\n value: string\n isMultiline?: boolean\n rows?: number\n}\n\nconst props = defineProps({\n value: null,\n isMultiline: { type: Boolean, default: false },\n rows: null\n})\n\nconst emit = defineEmits([\"copy\"])\n\nconst { copy } = useClipboard({ legacy: true })\n\nconst copied = ref(false)\n\nconst handleCopy = async () => {\n if (props.value) {\n await copy(props.value)\n copied.value = true\n emit('copy', props.value)\n\n setTimeout(() => {\n copied.value = false\n }, 2000)\n }\n}\n\nconst selectAllText = (event: Event) => {\n const textElement = event.target as HTMLElement\n\n const selection = window.getSelection()\n if (selection) {\n const range = document.createRange()\n range.selectNodeContents(textElement)\n selection.removeAllRanges()\n selection.addRange(range)\n }\n}\n</script>\n","import { getClientOperatingSystem, OperatingSystem } from '@speckle/shared'\n\nexport enum ModifierKeys {\n CtrlOrCmd = 'cmd-or-ctrl',\n AltOrOpt = 'alt-or-opt',\n Shift = 'shift'\n}\n\nexport const clientOs = getClientOperatingSystem()\n\nexport const ModifierKeyTitles: Record<ModifierKeys, string> = {\n [ModifierKeys.CtrlOrCmd]: clientOs === OperatingSystem.Mac ? 'Cmd' : 'Ctrl',\n [ModifierKeys.AltOrOpt]: clientOs === OperatingSystem.Mac ? 'Opt' : 'Alt',\n [ModifierKeys.Shift]: 'Shift'\n}\n\nexport function getKeyboardShortcutTitle(keys: Array<string | ModifierKeys>) {\n const isModifierKey = (k: string): k is ModifierKeys =>\n (Object.values(ModifierKeys) as string[]).includes(k)\n\n return keys.map((v) => (isModifierKey(v) ? ModifierKeyTitles[v] : v)).join('+')\n}\n","import { onKeyDown } from '@vueuse/core'\nimport { OperatingSystem } from '@speckle/shared'\nimport { clientOs, ModifierKeys } from '~~/src/helpers/form/input'\nimport { computed, ref } from 'vue'\nimport type { Ref } from 'vue'\n\n/**\n * onKeyDown wrapper that also checks for modifier keys being pressed\n */\nexport function onKeyboardShortcut(\n modifiers: ModifierKeys[],\n ...args: Parameters<typeof onKeyDown>\n) {\n onKeyDown(\n args[0],\n (e) => {\n const isAltOrOpt = e.getModifierState('Alt')\n const isCtrlOrCmd =\n clientOs === OperatingSystem.Mac\n ? e.getModifierState('Meta')\n : e.getModifierState('Control')\n const isShift = e.getModifierState('Shift')\n\n for (const modifier of modifiers) {\n switch (modifier) {\n case ModifierKeys.CtrlOrCmd:\n if (!isCtrlOrCmd) return\n break\n case ModifierKeys.AltOrOpt:\n if (!isAltOrOpt) return\n break\n case ModifierKeys.Shift:\n if (!isShift) return\n break\n }\n }\n\n args[1](e)\n },\n args[2]\n )\n}\n\n/**\n * To support group checkboxes, the checkbox v-model API is a bit confusing: The value is `true` or `undefined`\n * not `true` or `false`.\n *\n * To simplify working with single checkboxes, you can use the model returned from this composable\n * as the model and `isChecked` as a helpful wrapper that allows you to deal with boolean values only\n */\nexport function useFormCheckboxModel(\n options?: Partial<{\n model: Ref<true | undefined>\n }>\n) {\n const model = options?.model || ref<true | undefined>()\n const isChecked = computed({\n get: () => !!model.value,\n set: (newVal) => (model.value = newVal ? true : undefined)\n })\n\n return { model, isChecked }\n}\n","<template>\n <TransitionRoot as=\"template\" :show=\"open\">\n <Dialog as=\"div\" class=\"relative z-40\" @close=\"onClose\">\n <TransitionChild\n as=\"template\"\n enter=\"ease-out duration-300\"\n enter-from=\"opacity-0\"\n enter-to=\"opacity-100\"\n leave=\"ease-in duration-200\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n class=\"fixed inset-0 bg-neutral-100/70 dark:bg-neutral-900/70 transition-opacity backdrop-blur-xs\"\n />\n </TransitionChild>\n\n <div class=\"fixed inset-0 z-10 h-[100dvh] w-screen\">\n <div class=\"flex justify-center items-center h-full w-full p-4 sm:p-0\">\n <TransitionChild\n as=\"template\"\n enter=\"ease-out duration-300\"\n enter-from=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n enter-to=\"opacity-100 translate-y-0 sm:scale-100\"\n leave=\"ease-in duration-200\"\n leave-from=\"opacity-100 translate-y-0 sm:scale-100\"\n leave-to=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n @after-leave=\"$emit('fully-closed')\"\n >\n <DialogPanel\n :class=\"[\n 'transform rounded-lg text-foreground overflow-hidden bg-foundation text-left shadow-xl transition-all flex flex-col max-h-[90vh]',\n widthClasses\n ]\"\n :as=\"isForm ? 'form' : 'div'\"\n @submit.prevent=\"onSubmit || noop\"\n >\n <div :class=\"scrolledFromTop && 'relative z-20 shadow-lg'\">\n <div\n v-if=\"hasTitle\"\n class=\"flex items-center justify-start rounded-t-lg shrink-0 min-h-[2rem] sm:min-h-[4rem] py-2 px-4 sm:px-8 truncate text-lg sm:text-2xl font-bold\"\n >\n <div class=\"w-full truncate pr-12\">\n {{ title }}\n <slot name=\"header\"></slot>\n </div>\n </div>\n </div>\n\n <button\n v-if=\"!hideCloser\"\n class=\"absolute z-20 bg-foundation rounded-full p-1\"\n :class=\"hasTitle ? 'top-2 right-3 sm:top-4' : 'right-4 top-3'\"\n @click=\"open = false\"\n >\n <XMarkIcon class=\"h-5 sm:h-6 w-5 sm:w-6\" />\n </button>\n <div\n class=\"flex-1 simple-scrollbar overflow-y-auto\"\n :class=\"hasTitle ? 'p-3 sm:py-6 sm:px-8' : 'p-6 pt-10 sm:p-10'\"\n @scroll=\"onScroll\"\n >\n <slot>Put your content here!</slot>\n </div>\n <div\n v-if=\"hasButtons\"\n class=\"relative z-50 flex px-4 py-2 sm:py-4 sm:px-6 gap-2 shrink-0 bg-foundation\"\n :class=\"!scrolledToBottom && 'shadow-t'\"\n >\n <template v-if=\"buttons\">\n <FormButton\n v-for=\"(button, index) in buttons\"\n :key=\"index\"\n v-bind=\"button.props\"\n :disabled=\"button.disabled\"\n :type=\"button.submit && 'submit'\"\n @click=\"button.onClick\"\n >\n {{ button.text }}\n </FormButton>\n </template>\n <template v-else>\n <slot name=\"buttons\" />\n </template>\n </div>\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n</template>\n<script setup lang=\"ts\">\nimport { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'\nimport { FormButton } from '~~/src/lib'\nimport { XMarkIcon } from '@heroicons/vue/24/outline'\nimport { computed, ref, useSlots } from 'vue'\nimport { throttle, noop } from 'lodash'\n\ntype MaxWidthValue = 'sm' | 'md' | 'lg' | 'xl'\n\nconst emit = defineEmits([\"update:open\", \"fully-closed\"])\n\nconst props = defineProps({\n open: { type: Boolean },\n maxWidth: null,\n hideCloser: { type: Boolean },\n preventCloseOnClickOutside: { type: Boolean },\n title: null,\n buttons: null,\n onSubmit: { type: Function }\n})\n\nconst slots = useSlots()\n\nconst scrolledFromTop = ref(false)\nconst scrolledToBottom = ref(true)\n\nconst isForm = computed(() => !!props.onSubmit)\nconst hasButtons = computed(() => props.buttons || slots.buttons)\nconst hasTitle = computed(() => props.title || slots.header)\n\nconst open = computed({\n get: () => props.open,\n set: (newVal) => emit('update:open', newVal)\n})\n\nconst maxWidthWeight = computed(() => {\n switch (props.maxWidth) {\n case 'sm':\n return 0\n case 'md':\n return 1\n case 'lg':\n return 2\n case 'xl':\n return 3\n default:\n return 10000\n }\n})\n\nconst widthClasses = computed(() => {\n const classParts: string[] = ['w-full', 'sm:w-full sm:max-w-2xl']\n\n if (maxWidthWeight.value >= 1) {\n classParts.push('md:max-w-2xl')\n }\n if (maxWidthWeight.value >= 2) {\n classParts.push('lg:max-w-4xl')\n }\n if (maxWidthWeight.value >= 3) {\n classParts.push('xl:max-w-6xl')\n }\n if (maxWidthWeight.value >= 4) {\n classParts.push('2xl:max-w-7xl')\n }\n\n return classParts.join(' ')\n})\n\nconst onClose = () => {\n if (props.preventCloseOnClickOutside) return\n open.value = false\n}\n\nconst onScroll = throttle((e: Event) => {\n const target = e.target as HTMLElement\n const { scrollTop, offsetHeight, scrollHeight } = target\n scrolledFromTop.value = scrollTop > 0\n scrolledToBottom.value = scrollTop + offsetHeight >= scrollHeight\n}, 60)\n</script>\n","<template>\n <div\n class=\"flex flex-col border-primary-muted\"\n :class=\"{\n 'border-t': borderT,\n 'border-b': borderB,\n 'relative z-10': isExpanded\n }\"\n >\n <div\n class=\"flex justify-between items-center gap-4 sm:gap-8 py-3 sm:py-4 px-2\"\n :class=\"backgroundClass\"\n tabindex=\"0\"\n v-on=\"\n !button && !alwaysOpen\n ? {\n click: toggleExpansion,\n keypress: keyboardClick(toggleExpansion)\n }\n : {}\n \"\n >\n <div\n class=\"text-sm sm:text-base font-bold flex items-center gap-1 sm:gap-2 select-none\"\n :class=\"titleClasses\"\n >\n <div class=\"h-4 sm:h-5 w-4 sm:w-5 empty:h-0 empty:w-0\">\n <slot name=\"icon\"></slot>\n </div>\n <span>{{ title }}</span>\n </div>\n <div>\n <ChevronDownIcon\n v-if=\"!button && !alwaysOpen\"\n class=\"w-4 h-4 sm:w-5 sm:h-5 transition-all duration-400\"\n :class=\"isExpanded && 'rotate-180'\"\n />\n <FormButton\n v-if=\"button\"\n size=\"sm\"\n :to=\"button.expandContent ? undefined : button.to\"\n :color=\"button.expandContent && isExpanded ? 'invert' : button.color\"\n :icon-right=\"\n button.expandContent && isExpanded ? undefined : button.iconRight\n \"\n @click=\"button?.onClick\"\n v-on=\"button?.expandContent ? { click: toggleExpansion } : {}\"\n >\n {{ button.expandContent && isExpanded ? 'Cancel' : button.text }}\n </FormButton>\n </div>\n </div>\n <div\n class=\"transition-all duration-700 overflow-hidden\"\n :class=\"[\n allowOverflow && isExpanded ? '!overflow-visible' : '',\n isExpanded ? 'mb-3 mt-1' : '',\n !button && !alwaysOpen ? 'cursor-pointer hover:bg-foundation' : ''\n ]\"\n :style=\"\n alwaysOpen\n ? 'max-height: none;'\n : `max-height: ${isExpanded ? contentHeight + 'px' : '0px'}`\n \"\n >\n <template v-if=\"props.lazyLoad\">\n <div\n v-if=\"isExpanded || props.alwaysOpen\"\n ref=\"content\"\n class=\"rounded-md text-sm pb-3 px-2 mt-1\"\n >\n <slot>Panel contents</slot>\n </div>\n </template>\n\n <template v-else>\n <div ref=\"content\" class=\"rounded-md text-sm pb-3 px-2 mt-1\">\n <slot>Panel contents</slot>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, unref, computed, nextTick } from 'vue'\nimport type { Ref } from 'vue'\nimport { ChevronDownIcon } from '@heroicons/vue/24/outline'\nimport { FormButton } from '~~/src/lib'\nimport { keyboardClick } from '~~/src/helpers/global/accessibility'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype TitleColor = 'default' | 'danger' | 'warning' | 'success' | 'secondary' | 'info'\n\ntype FormButtonColor =\n | 'default'\n | 'invert'\n | 'danger'\n | 'warning'\n | 'success'\n | 'card'\n | 'secondary'\n | 'info'\n\nconst props = defineProps({\n title: String,\n borderT: Boolean,\n borderB: Boolean,\n allowOverflow: Boolean,\n titleColor: {\n type: String as () => TitleColor,\n default: 'default'\n },\n button: Object as () =>\n | {\n expandContent?: boolean\n text: string\n to?: string\n color: FormButtonColor\n iconRight?: PropAnyComponent | undefined\n onClick?: () => void\n }\n | undefined,\n alwaysOpen: Boolean,\n lazyLoad: {\n type: Boolean,\n default: false\n }\n})\n\nconst content: Ref<HTMLElement | null> = ref(null)\nconst contentHeight = ref(0)\nconst isExpanded = ref(false)\n\nconst backgroundClass = computed(() => {\n const classes = []\n\n if (!props.button && !props.alwaysOpen) {\n classes.push('cursor-pointer', 'hover:bg-foundation')\n }\n\n if (isExpanded.value) {\n classes.push('bg-foundation')\n }\n\n return classes\n})\n\nconst titleClasses = computed(() => {\n switch (props.titleColor) {\n case 'danger':\n return 'text-danger'\n case 'warning':\n return 'text-warning'\n case 'success':\n return 'text-success'\n case 'secondary':\n return 'text-secondary'\n case 'info':\n return 'text-info'\n default:\n return 'text-foreground'\n }\n})\n\nconst toggleExpansion = async () => {\n isExpanded.value = !isExpanded.value\n\n if (isExpanded.value) {\n await nextTick()\n contentHeight.value = (unref(content)?.scrollHeight || 0) + 64\n }\n}\n</script>\n","<template>\n <div>\n <Disclosure v-slot=\"{ open }\">\n <DisclosureButton :class=\"buttonClasses\">\n <div class=\"inline-flex items-center space-x-2\">\n <Component :is=\"icon\" v-if=\"icon\" class=\"h-5 w-5\" />\n <span>{{ title }}</span>\n </div>\n <ChevronUpIcon :class=\"!open ? 'rotate-180 transform' : ''\" class=\"h-5 w-5\" />\n </DisclosureButton>\n <DisclosurePanel :class=\"panelClasses\">\n <div class=\"label-light\">\n <slot>Panel contents</slot>\n </div>\n </DisclosurePanel>\n </Disclosure>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { DisclosureButton, Disclosure, DisclosurePanel } from '@headlessui/vue'\nimport { ChevronUpIcon } from '@heroicons/vue/24/solid'\nimport { computed } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype DisclosureColor = 'default' | 'danger' | 'success' | 'warning'\n\nconst props = defineProps({\n title: null,\n icon: null,\n color: { default: 'default' }\n})\n\nconst buttonClasses = computed(() => {\n const classParts = [\n 'pr-3 h-10 w-full flex items-center justify-between border-l-2 px-2 rounded transition',\n 'ring-1 font-medium'\n ]\n\n switch (props.color) {\n case 'warning':\n classParts.push(\n 'border-warning text-warning ring-warning-lighter hover:ring-warning'\n )\n break\n case 'success':\n classParts.push(\n 'border-success text-success ring-success-lighter hover:ring-success'\n )\n break\n case 'danger':\n classParts.push('border-danger text-danger ring-danger-lighter hover:ring-danger')\n break\n case 'default':\n default:\n classParts.push(\n 'border-primary text-primary ring-primary-muted hover:ring-primary'\n )\n break\n }\n\n return classParts.join(' ')\n})\n\nconst panelClasses = computed(() => {\n const classParts = ['p-3 border-x border-b rounded-b-md']\n\n switch (props.color) {\n case 'warning':\n classParts.push('border-warning-lighter')\n break\n case 'success':\n classParts.push('border-success-lighter')\n break\n case 'danger':\n classParts.push('border-danger-lighter')\n break\n case 'default':\n default:\n classParts.push('border-primary-muted')\n break\n }\n\n return classParts.join(' ')\n})\n</script>\n","import type { ConcreteComponent } from 'vue'\n\nexport enum GridListToggleValue {\n Grid = 'grid',\n List = 'list'\n}\n\nexport type LayoutTabItem<I extends string = string> = {\n title: string\n id: I\n}\n\nexport type LayoutPageTabItem<I extends string = string> = {\n title: string\n id: I\n icon: ConcreteComponent\n count?: number\n tag?: string\n}\n\nexport type LayoutMenuItem<I extends string = string> = {\n icon?: ConcreteComponent\n title: string\n id: I\n disabled?: boolean\n disabledTooltip?: string\n color?: 'danger' | 'info'\n}\n","<template>\n <button\n class=\"max-w-max transition flex justify-center items-center gap-2 outline-none select-none h-8 text-foreground border-2 border-primary-muted dark:border-foundation bg-primary-muted rounded-md active:scale-[0.97] grow\"\n @click=\"onClick\"\n >\n <div class=\"relative flex bg-primary-muted rounded-md\">\n <div\n class=\"absolute transition\"\n :class=\"{\n 'translate-x-7': value !== GridListToggleValue.Grid\n }\"\n >\n <div\n class=\"w-7 h-7 bg-foundation dark:bg-foundation-2 transition rounded shadow\"\n />\n </div>\n <div\n v-tippy=\"'Grid View'\"\n class=\"relative z-10 flex gap-1 items-center p-1 rounded-l\"\n >\n <Squares2X2Icon class=\"h-5 w-5\" />\n </div>\n <div\n v-tippy=\"'List View'\"\n class=\"relative z-10 flex gap-1 items-center p-1 rounded-r\"\n >\n <Bars3Icon class=\"h-5 w-5\" />\n </div>\n </div>\n </button>\n</template>\n\n<script setup lang=\"ts\">\nimport { Bars3Icon, Squares2X2Icon } from '@heroicons/vue/24/solid'\nimport { computed } from 'vue'\nimport { GridListToggleValue } from '~~/src/helpers/layout/components'\n\nconst emit = defineEmits([\"click\", \"update:modelValue\"])\n\nconst props = defineProps({\n modelValue: null\n})\n\nconst value = computed({\n get: () => props.modelValue || GridListToggleValue.Grid,\n set: (newVal) => emit('update:modelValue', newVal)\n})\n\nconst onClick = (e: MouseEvent) => {\n emit('click', e)\n\n const newVal =\n value.value === GridListToggleValue.Grid\n ? GridListToggleValue.List\n : GridListToggleValue.Grid\n value.value = newVal\n}\n</script>\n","import type { Nullable } from '@speckle/shared'\nimport { isClient } from '@vueuse/core'\nimport type { MaybeRef } from '@vueuse/core'\nimport { debounce, isUndefined, throttle } from 'lodash'\nimport { computed, onBeforeUnmount, onMounted, ref, unref, watch } from 'vue'\n\nexport enum ThrottleOrDebounce {\n Throttle,\n Debounce\n}\n\nexport enum HorizontalDirection {\n Left,\n Right\n}\n\nexport function useWindowResizeHandler(\n handler: (e: UIEvent) => void,\n options?: Partial<{\n wait: number\n throttleOrDebounce: ThrottleOrDebounce\n }>\n) {\n if (!isClient) return\n\n const { wait = 100, throttleOrDebounce = ThrottleOrDebounce.Throttle } = options || {}\n const finalHandler = wait\n ? throttleOrDebounce === ThrottleOrDebounce.Throttle\n ? throttle(handler, wait)\n : debounce(handler, wait)\n : handler\n\n onMounted(() => window.addEventListener('resize', finalHandler))\n onBeforeUnmount(() => window.removeEventListener('resize', finalHandler))\n}\n\nexport function useOnBeforeWindowUnload(handler: (e: BeforeUnloadEvent) => void) {\n onMounted(() => {\n window.addEventListener('beforeunload', handler)\n })\n\n onBeforeUnmount(() => {\n window.removeEventListener('beforeunload', handler)\n })\n}\n\nexport function useResponsiveHorizontalDirectionCalculation(params: {\n el: MaybeRef<Nullable<HTMLElement>>\n defaultDirection?: HorizontalDirection\n /**\n * Stop recalculation below this screen size. Defaults to el.width * 2\n */\n stopUpdatesBelowWidth?: MaybeRef<number>\n}) {\n const { el, defaultDirection } = params\n\n const direction = ref<HorizontalDirection>(\n !isUndefined(defaultDirection) ? defaultDirection : HorizontalDirection.Right\n )\n const stopUpdatesBelowWidth = computed(() => {\n const stopUpdatesBelowWidth = unref(params.stopUpdatesBelowWidth)\n if (!isUndefined(stopUpdatesBelowWidth)) return stopUpdatesBelowWidth\n\n const element = unref(el)\n return element?.offsetWidth ? element.offsetWidth * 2 : undefined\n })\n\n const recalculateDirection = () => {\n if (!isClient) return\n\n const element = unref(el)\n if (!element) return\n\n const rect = element.getBoundingClientRect()\n const showOnLeftSide = rect.x + rect.width > window.innerWidth\n const showOnRightSide = rect.x < 0\n\n // Screen too small - do nothing\n if (\n (showOnLeftSide && showOnRightSide) ||\n (!isUndefined(stopUpdatesBelowWidth.value) &&\n window.innerWidth < stopUpdatesBelowWidth.value)\n )\n return\n\n if (showOnLeftSide) {\n direction.value = HorizontalDirection.Left\n } else if (showOnRightSide) {\n direction.value = HorizontalDirection.Right\n }\n }\n\n useWindowResizeHandler(() => recalculateDirection())\n\n watch(\n () => unref(el),\n (element) => {\n if (element) {\n recalculateDirection()\n }\n }\n )\n\n return {\n direction: computed(() => direction.value),\n recalculateDirection\n }\n}\n","<template>\n <Menu v-slot=\"{ open: isMenuOpen }\" as=\"div\" class=\"relative inline-block\">\n <div>\n <MenuButton ref=\"menuButton\" class=\"hidden\" @click.stop.prevent />\n <!-- conditional pointer-events-none is necessary to avoid double events when clicking on the button when the menu is already open -->\n <div :class=\"isMenuOpen ? 'pointer-events-none' : ''\">\n <slot :toggle=\"toggle\" :open=\"processOpen(isMenuOpen)\" />\n </div>\n </div>\n <Transition\n enter-active-class=\"transition duration-100 ease-out\"\n enter-from-class=\"transform scale-95 opacity-0\"\n enter-to-class=\"transform scale-100 opacity-100\"\n leave-active-class=\"transition duration-75 ease-in\"\n leave-from-class=\"transform scale-100 opacity-100\"\n leave-to-class=\"transform scale-95 opacity-0\"\n >\n <MenuItems\n ref=\"menuItems\"\n :class=\"[\n 'absolute mt-2 w-48 origin-top-right divide-y divide-outline-3 rounded-md bg-foundation shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none z-40',\n menuDirection === HorizontalDirection.Left ? 'right-0' : ''\n ]\"\n >\n <div v-for=\"(group, i) in items\" :key=\"i\" class=\"p-1\">\n <MenuItem\n v-for=\"item in group\"\n v-slot=\"{ active, disabled }\"\n :key=\"item.id\"\n :disabled=\"item.disabled\"\n :color=\"item.color\"\n >\n <span v-tippy=\"item.disabled && item.disabledTooltip\">\n <button\n :class=\"buildButtonClassses({ active, disabled, color: item.color })\"\n :disabled=\"disabled\"\n @click=\"chooseItem(item, $event)\"\n >\n <Component :is=\"item.icon\" v-if=\"item.icon\" class=\"h-5 w-5\" />\n <slot name=\"item\" :item=\"item\">{{ item.title }}</slot>\n </button>\n </span>\n </MenuItem>\n </div>\n </MenuItems>\n </Transition>\n </Menu>\n</template>\n<script setup lang=\"ts\">\nimport { directive as vTippy } from 'vue-tippy'\nimport { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref, watch } from 'vue'\nimport {\n HorizontalDirection,\n useResponsiveHorizontalDirectionCalculation\n} from '~~/src/composables/common/window'\nimport type { LayoutMenuItem } from '~~/src/helpers/layout/components'\n\nconst emit = defineEmits([\"update:open\", \"chosen\"])\n\nconst props = defineProps({\n open: { type: Boolean },\n items: null\n})\n\nconst menuItems = ref(null as Nullable<{ el: HTMLDivElement }>)\nconst { direction: menuDirection } = useResponsiveHorizontalDirectionCalculation({\n el: computed(() => menuItems.value?.el || null),\n defaultDirection: HorizontalDirection.Left,\n stopUpdatesBelowWidth: 300\n})\n\nconst menuButton = ref(null as Nullable<{ el: HTMLButtonElement }>)\nconst isOpenInternally = ref(false)\n\nconst finalOpen = computed({\n get: () => props.open || false,\n set: (newVal) => emit('update:open', newVal)\n})\n\nconst buildButtonClassses = (params: {\n active?: boolean\n disabled?: boolean\n color?: 'danger' | 'info'\n}) => {\n const { active, disabled, color } = params\n const classParts = [\n 'group flex gap-3 w-full items-center rounded-md px-2 py-1.5 text-sm'\n ]\n\n if (active && !color) {\n classParts.push('bg-foundation-focus text-foreground')\n } else if (disabled) {\n classParts.push('text-foreground-disabled')\n } else if (color === 'danger' && active) {\n classParts.push('text-foreground-on-primary bg-danger')\n } else if (color === 'danger' && !active) {\n classParts.push('text-danger')\n } else if (color === 'info' && active) {\n classParts.push('text-foreground-on-primary bg-info')\n } else if (color === 'info' && !active) {\n classParts.push('text-info')\n } else {\n classParts.push('text-foreground')\n }\n\n return classParts.join(' ')\n}\n\nconst chooseItem = (item: LayoutMenuItem, event: MouseEvent) => {\n emit('chosen', { item, event })\n}\n\nconst toggle = () => menuButton.value?.el.click()\n\n// ok this is a bit hacky, but it's done because of headlessui's limited API\n// the point of this is 1) cast any to bool 2) store 'open' state locally\n// so that we can access it outside of the template\nconst processOpen = (val: unknown): val is boolean => {\n const isOpen = !!val\n isOpenInternally.value = isOpen\n return isOpen\n}\n\nwatch(isOpenInternally, (newVal, oldVal) => {\n if (newVal === oldVal) return\n finalOpen.value = newVal\n})\n\nwatch(finalOpen, (shouldBeOpen) => {\n if (shouldBeOpen && !isOpenInternally.value) {\n toggle()\n } else if (!shouldBeOpen && isOpenInternally.value) {\n toggle()\n }\n})\n</script>\n","<template>\n <div class=\"flex flex-col gap-y-0 sm:gap-y-4\">\n <div class=\"flex gap-x-6\">\n <FormButton\n v-for=\"item in items\"\n :key=\"item.id\"\n link\n :color=\"activeItem.id === item.id ? 'default' : 'secondary'\"\n @click=\"onTabClick(item)\"\n >\n {{ item.title }}\n </FormButton>\n </div>\n <slot :active-item=\"activeItem\" />\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref } from 'vue'\nimport type { LayoutTabItem } from '~~/src/helpers/layout/components'\nimport FormButton from '~~/src/components/form/Button.vue'\n\nconst props = defineProps({\n items: null\n})\n\nconst activeItemId = ref(null as Nullable<string>)\nconst activeItem = computed(() => {\n if (!activeItemId.value) return props.items[0]\n return props.items.find((i) => i.id === activeItemId.value) || props.items[0]\n})\n\nconst onTabClick = (item: LayoutTabItem) => {\n activeItemId.value = item.id\n}\n</script>\n","<template>\n <div\n class=\"relative z-10 flex gap-4\"\n :class=\"vertical ? 'sm:gap-8 flex-col sm:flex-row' : 'sm:gap-10 flex-col'\"\n >\n <div\n class=\"relative flex sm:justify-between overflow-x-auto\"\n :class=\"\n vertical\n ? 'items-center sm:items-start sm:flex-col sm:w-2/12 border-r border-outline gap-4 pl-4'\n : 'border-b border-outline-3 lg:border-none gap-8 w-full'\n \"\n >\n <template v-if=\"!vertical\">\n <div\n class=\"hidden lg:block absolute bottom-0 left-0 h-px w-full bg-outline-3\"\n ></div>\n <div\n :style=\"borderStyle\"\n class=\"h-[2px] absolute bottom-0 z-20 bg-primary transition-all duration-300\"\n ></div>\n </template>\n\n <div\n ref=\"buttonContainer\"\n class=\"flex\"\n :class=\"\n vertical ? 'flex-wrap sm:flex-nowrap flex-row sm:flex-col gap-4' : 'gap-6'\n \"\n >\n <h1\n v-if=\"title\"\n class=\"font-bold h4\"\n :class=\"vertical ? 'w-full sm:w-auto -ml-4 mb-4' : 'mb-2'\"\n >\n {{ title }}\n </h1>\n <button\n v-for=\"item in items\"\n :key=\"item.id\"\n :data-tab-id=\"item.id\"\n class=\"tab-button relative z-10 flex items-center gap-1.5 pb-2 border-b-[2px] border-transparent text-base max-w-max px-2\"\n :class=\"[\n activeItem.id === item.id\n ? 'text-primary hover:text-primary'\n : 'text-foreground',\n vertical ? 'hover:border-outline' : 'hover:border-outline-2'\n ]\"\n @click=\"onTabClick(item)\"\n >\n <Component\n :is=\"item.icon\"\n v-if=\"item.icon\"\n class=\"shrink-0 h-4 w-4 stroke-[2px]\"\n />\n <span class=\"min-w-6\">{{ item.title }}</span>\n <div\n v-if=\"item.count\"\n class=\"rounded-full px-2 text-[11px] transition-all min-w-6\"\n :class=\"\n activeItem.id === item.id\n ? 'text-primary bg-blue-100'\n : 'text-foreground-2 bg-gray-200 dark:bg-foundation'\n \"\n >\n <span>{{ item.count }}</span>\n </div>\n <div\n v-if=\"item.tag\"\n class=\"text-[10px] leading-tight py-0.5 text-foreground-on-primary font-medium px-1.5 rounded-full bg-gradient-to-tr from-[#7025EB] to-primary select-none mt-0.5\"\n >\n {{ item.tag }}\n </div>\n </button>\n </div>\n </div>\n <div :class=\"vertical ? 'sm:w-10/12' : ''\">\n <slot :active-item=\"activeItem\" />\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { computed, ref, watch, type CSSProperties } from 'vue'\nimport type { LayoutPageTabItem } from '~~/src/helpers/layout/components'\nimport { isClient } from '@vueuse/core'\nimport type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'\n\nconst props = defineProps({\n items: null,\n vertical: { type: Boolean },\n title: null\n})\n\nconst buttonContainer = ref(null as Nullable<HTMLDivElement>)\nconst activeItemId = ref<string | null>(null)\n\nconst activeItem = computed(() => {\n const item = props.items.find((i) => i.id === activeItemId.value)\n return item || props.items[0]\n})\n\nconst activeItemRef = computed(() => {\n const id = activeItemId.value\n if (!id) return null\n\n const parent = buttonContainer.value\n if (!parent) return null\n\n const btns = [...parent.getElementsByClassName('tab-button')] as HTMLButtonElement[]\n return btns.find((b) => b.dataset['tabId'] === id) || null\n})\n\nconst borderStyle = computed(() => {\n const element = activeItemRef.value\n const style: CSSProperties = {\n left: `${element?.offsetLeft || 0}px`,\n width: `${element?.clientWidth || 0}px`\n }\n return style\n})\n\nconst onTabClick = (item: LayoutPageTabItem) => {\n activeItemId.value = item.id\n}\n\nconst setActiveItem = (item: MaybeNullOrUndefined<LayoutPageTabItem>) => {\n if (!isClient || !item?.id) return\n\n activeItemId.value = item.id\n}\n\nwatch(\n () => props.items,\n (newItems) => {\n setActiveItem(newItems[0])\n },\n { immediate: true }\n)\n</script>\n","<template>\n <div class=\"text-foreground\">\n <div class=\"w-full text-sm overflow-x-auto overflow-y-visible simple-scrollbar\">\n <div\n v-if=\"items.length > 0\"\n class=\"grid z-10 grid-cols-12 items-center gap-6 font-semibold bg-foundation rounded-t-lg w-full border-b border-outline-3 pb-2 pt-4 px-4 min-w-[900px]\"\n :style=\"{ paddingRight: paddingRightStyle }\"\n >\n <div\n v-for=\"column in columns\"\n :key=\"column.id\"\n :class=\"getHeaderClasses(column.id)\"\n class=\"capitalize\"\n >\n {{ column.header }}\n </div>\n </div>\n <div\n class=\"divide-y divide-outline-3 h-full overflow-visible\"\n :class=\"{ 'pb-32': overflowCells }\"\n >\n <div\n v-for=\"item in items\"\n :key=\"item.id\"\n :style=\"{ paddingRight: paddingRightStyle }\"\n :class=\"rowsWrapperClasses\"\n tabindex=\"0\"\n @click=\"handleRowClick(item)\"\n @keypress=\"handleRowClick(item)\"\n >\n <template v-for=\"(column, colIndex) in columns\" :key=\"column.id\">\n <div :class=\"getClasses(column.id, colIndex)\" tabindex=\"0\">\n <slot :name=\"column.id\" :item=\"item\">\n <div class=\"text-gray-900 font-medium order-1\">Placeholder</div>\n </slot>\n </div>\n </template>\n <div class=\"absolute right-1.5 gap-1 flex items-center p-0 h-full\">\n <div v-for=\"button in buttons\" :key=\"button.label\">\n <FormButton\n :icon-left=\"button.icon\"\n size=\"sm\"\n color=\"secondary\"\n hide-text\n :class=\"button.class\"\n :text-color=\"button.textColor\"\n :to=\"isString(button.action) ? button.action : undefined\"\n @click.stop=\"!isString(button.action) ? button.action(item) : noop\"\n />\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"T extends {id: string}, C extends string\">\nimport { noop, isString } from 'lodash'\nimport { computed } from 'vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\nimport type { FormButtonTextColor } from '~~/src/helpers/form/button'\nimport { FormButton } from '~~/src/lib'\n\nexport type TableColumn<I> = {\n id: I\n header: string\n classes: string\n}\n\nexport interface RowButton<T = unknown> {\n icon: PropAnyComponent\n label: string\n action: (item: T) => void | string\n class?: string\n textColor?: FormButtonTextColor\n}\n\nconst props = defineProps({\n items: null,\n buttons: null,\n columns: null,\n overflowCells: { type: Boolean },\n onRowClick: { type: Function },\n rowItemsAlign: { default: 'center' }\n})\n\nconst paddingRightStyle = computed(() => {\n const buttonCount = (props.buttons || []).length\n let padding = 16\n if (buttonCount > 0) {\n padding = 48 + (buttonCount - 1) * 42\n }\n return `${padding}px`\n})\n\nconst rowsWrapperClasses = computed(() => {\n const classParts = [\n 'relative grid grid-cols-12 items-center gap-6 px-4 py-1 min-w-[900px] bg-foundation'\n ]\n\n if (props.onRowClick) {\n classParts.push('cursor-pointer hover:bg-primary-muted')\n }\n\n switch (props.rowItemsAlign) {\n case 'center':\n classParts.push('items-center')\n break\n case 'stretch':\n classParts.push('items-stretch')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst getHeaderClasses = (column: C): string => {\n return props.columns.find((c) => c.id === column)?.classes || ''\n}\n\nconst getClasses = (column: C, colIndex: number): string => {\n const columnClass = getHeaderClasses(column)\n\n if (colIndex === 0) {\n return `bg-transparent py-3 pr-5 px-1 ${columnClass}`\n }\n return `lg:p-0 px-1 my-2 ${columnClass}`\n}\n\nconst handleRowClick = (item: T) => {\n props.onRowClick?.(item)\n}\n</script>\n","<template>\n <div ref=\"wrapper\">\n <InternalInfiniteLoading\n v-if=\"initializeLoader\"\n v-bind=\"$props.settings || {}\"\n @infinite=\"$emit('infinite', $event)\"\n >\n <template #spinner>\n <CommonLoadingBar :loading=\"true\" class=\"my-2\" />\n </template>\n <template #complete>\n <!-- No \"No more items\" message, instead a small amount of spacing -->\n <div class=\"h-8\"></div>\n </template>\n <template #error=\"{ retry }\">\n <div class=\"w-full flex flex-col items-center my-2 space-y-2 mt-4\">\n <div class=\"inline-flex items-center space-x-1\">\n <ExclamationTriangleIcon class=\"w-5 h-5 text-danger\" />\n <span class=\"text-foreground-2\">An error occurred while loading</span>\n </div>\n <FormButton v-if=\"allowRetry\" @click=\"retry\">Retry</FormButton>\n </div>\n </template>\n </InternalInfiniteLoading>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport InternalInfiniteLoading from 'v3-infinite-loading'\nimport { ExclamationTriangleIcon } from '@heroicons/vue/24/outline'\nimport type { InfiniteLoaderState } from '~~/src/helpers/global/components'\nimport type { Nullable } from '@speckle/shared'\nimport CommonLoadingBar from '~~/src/components/common/loading/Bar.vue'\nimport { onMounted, ref } from 'vue'\nimport { isClient } from '@vueuse/core'\nimport FormButton from '~~/src/components/form/Button.vue'\n\ndefineEmits([\"infinite\"])\n\ndefineProps({\n settings: null,\n allowRetry: { type: Boolean }\n})\n\nconst wrapper = ref(null as Nullable<HTMLElement>)\nconst initializeLoader = ref(false)\n\n// This hack is necessary cause sometimes v3-infinite-loading initializes too early and doesnt trigger\nif (isClient) {\n onMounted(() => {\n const int = setInterval(() => {\n if (wrapper.value?.isConnected) {\n initializeLoader.value = true\n clearInterval(int)\n }\n }, 200)\n })\n}\n</script>\n","<template>\n <div class=\"relative group\">\n <div\n v-if=\"fancyGlow\"\n class=\"absolute -inset-1 bg-blue-300 dark:bg-blue-500 opacity-5 dark:opacity-0 rounded-md blur-sm group-hover:opacity-60 dark:group-hover:opacity-30 transition duration-500\"\n ></div>\n <Component\n :is=\"form ? 'form' : 'div'\"\n :class=\"[\n 'relative divide-outline-3 bg-foundation text-foreground flex flex-col divide-y overflow-hidden',\n computedClasses\n ]\"\n @submit=\"emit('submit', $event)\"\n >\n <div v-if=\"$slots.header\" :class=\"secondarySlotPaddingClasses\">\n <slot name=\"header\" />\n </div>\n <div :class=\"['grow', defaultSlotPaddingClasses]\">\n <slot />\n </div>\n <div v-if=\"$slots.footer\" :class=\"secondarySlotPaddingClasses\">\n <slot name=\"footer\" />\n </div>\n </Component>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst emit = defineEmits([\"submit\"])\n\nconst props = defineProps({\n /**\n * Use a `<form/>` element as a wrapper that will emit 'submit' events out from the component when they occur\n */\n form: {\n type: Boolean,\n default: false\n },\n /**\n * Add a ring outline on hover\n */\n ring: {\n type: Boolean,\n default: false\n },\n /**\n * Add a primary-colored glow on hover\n */\n fancyGlow: {\n type: Boolean,\n default: false\n },\n customPadding: {\n type: Boolean,\n default: false\n },\n noShadow: {\n type: Boolean,\n default: false\n },\n panelClasses: {\n type: String\n }\n})\n\nconst secondarySlotPaddingClasses = computed(() =>\n props.customPadding ? '' : 'px-4 py-4 sm:px-6'\n)\nconst defaultSlotPaddingClasses = computed(() =>\n props.customPadding ? '' : 'px-4 py-4 sm:p-6'\n)\n\nconst computedClasses = computed(() => {\n const classParts: string[] = ['rounded-lg']\n\n if (!props.noShadow) classParts.push('shadow')\n if (props.ring) {\n classParts.push('ring-outline-2 hover:ring-2')\n }\n if (props.panelClasses) {\n classParts.push(props.panelClasses)\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <div class=\"rounded-md\" :class=\"[containerClasses, textClasses]\">\n <div class=\"flex\" :class=\"subcontainerClasses\">\n <div class=\"flex-shrink-0\">\n <Component :is=\"icon\" :class=\"iconClasses\" aria-hidden=\"true\" />\n </div>\n <div :class=\"mainContentContainerClasses\">\n <h3 class=\"text-sm\" :class=\"[hasDescription ? 'font-medium' : '']\">\n <slot name=\"title\">Title</slot>\n </h3>\n <div v-if=\"hasDescription\" :class=\"descriptionWrapperClasses\">\n <slot name=\"description\">\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquid pariatur,\n ipsum similique veniam.\n </slot>\n </div>\n <div :class=\"actionsContainerClasses\">\n <FormButton\n v-for=\"(action, i) in actions || []\"\n :key=\"i\"\n :color=\"color\"\n :size=\"actionSize\"\n :to=\"action.url\"\n :external=\"action.externalUrl || false\"\n @click=\"action.onClick || noop\"\n >\n {{ action.title }}\n </FormButton>\n </div>\n </div>\n <div\n v-if=\"withDismiss\"\n class=\"flex\"\n :class=\"[hasDescription ? 'items-start' : 'items-center']\"\n >\n <button\n type=\"button\"\n class=\"inline-flex rounded-md focus:outline-none focus:ring-2\"\n :class=\"buttonClasses\"\n @click=\"$emit('dismiss')\"\n >\n <span class=\"sr-only\">Dismiss</span>\n <XMarkIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n CheckCircleIcon,\n XMarkIcon,\n XCircleIcon,\n InformationCircleIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/20/solid'\nimport { noop } from 'lodash'\nimport { computed, useSlots } from 'vue'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\n\ntype AlertColor = 'success' | 'danger' | 'warning' | 'info'\ntype Size = 'default' | 'xs'\n\ndefineEmits([\"dismiss\"])\n\nconst props = defineProps({\n color: { default: 'success' },\n withDismiss: { type: Boolean },\n actions: null,\n customIcon: null,\n size: { default: 'default' }\n})\n\nconst slots = useSlots()\nconst hasDescription = computed(() => !!slots['description'])\n\nconst icon = computed(() => {\n if (props.customIcon) return props.customIcon\n\n switch (props.color) {\n case 'info':\n return InformationCircleIcon\n case 'warning':\n return ExclamationCircleIcon\n case 'danger':\n return XCircleIcon\n case 'success':\n default:\n return CheckCircleIcon\n }\n})\n\nconst containerClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case 'xs':\n classParts.push('p-1')\n break\n case 'default':\n default:\n classParts.push(hasDescription.value ? 'p-3 sm:p-4' : 'p-2')\n break\n }\n\n switch (props.color) {\n case 'success':\n classParts.push('bg-success-lighter border-l-4 border-success')\n break\n case 'info':\n classParts.push('bg-info-lighter border-l-4 border-info')\n break\n case 'danger':\n classParts.push('bg-danger-lighter border-l-4 border-danger')\n break\n case 'warning':\n classParts.push('bg-warning-lighter border-l-4 border-warning')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst subcontainerClasses = computed(() => {\n const classParts: string[] = []\n\n if (hasDescription.value) {\n classParts.push('')\n } else {\n classParts.push('items-center')\n\n switch (props.size) {\n case 'xs':\n classParts.push('space-x-1')\n break\n case 'default':\n default:\n classParts.push('space-x-2')\n break\n }\n }\n\n return classParts.join(' ')\n})\n\nconst mainContentContainerClasses = computed(() => {\n const classParts: string[] = ['grow']\n\n if (!hasDescription.value) {\n classParts.push('flex items-center space-x-2')\n }\n\n switch (props.size) {\n case 'xs':\n classParts.push('ml-1')\n break\n case 'default':\n default:\n classParts.push('ml-3')\n\n break\n }\n\n return classParts.join(' ')\n})\n\nconst descriptionWrapperClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case 'xs':\n classParts.push('text-xs')\n break\n case 'default':\n default:\n classParts.push('mt-1 sm:mt-2 text-xs sm:text-sm')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst actionsContainerClasses = computed(() => {\n const classParts: string[] = ['flex']\n\n if (!hasDescription.value) {\n classParts.push('grow justify-end')\n }\n\n const hasDescriptionAndActions = hasDescription.value && props.actions?.length\n\n switch (props.size) {\n case 'xs':\n classParts.push('space-x-1')\n if (hasDescriptionAndActions) {\n classParts.push('mt-1')\n }\n break\n case 'default':\n default:\n classParts.push('space-x-2')\n if (hasDescriptionAndActions) {\n classParts.push('mt-4')\n }\n break\n }\n\n return classParts.join(' ')\n})\n\nconst textClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.color) {\n case 'success':\n classParts.push('text-success-darker')\n break\n case 'info':\n classParts.push('text-info-darker')\n break\n case 'danger':\n classParts.push('text-danger-darker')\n break\n case 'warning':\n classParts.push('text-warning-darker')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case 'xs':\n classParts.push('h-4 w-4')\n classParts.push(hasDescription.value ? 'mt-0.5' : '')\n break\n case 'default':\n default:\n classParts.push('h-5 w-5')\n break\n }\n\n switch (props.color) {\n case 'success':\n classParts.push('text-success')\n break\n case 'info':\n classParts.push('text-info')\n break\n case 'danger':\n classParts.push('text-danger')\n break\n case 'warning':\n classParts.push('text-warning')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst buttonClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.color) {\n case 'success':\n classParts.push('bg-success-lighter ring-success')\n break\n case 'info':\n classParts.push('bg-info-lighter ring-info')\n break\n case 'danger':\n classParts.push('bg-danger-lighter ring-danger')\n break\n case 'warning':\n classParts.push('bg-warning-lighter ring-warning')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst actionSize = computed(() => {\n switch (props.size) {\n case 'xs':\n return 'xs'\n case 'default':\n default:\n return 'sm'\n }\n})\n</script>\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { MaybeAsync } from '@speckle/shared'\nimport { computedAsync } from '@vueuse/core'\nimport type { AsyncComputedOptions } from '@vueuse/core'\nimport { computed } from 'vue'\nimport type { ComputedRef } from 'vue'\n\nexport interface AsyncWritableComputedOptions<T> {\n get: (...args: any[]) => MaybeAsync<T>\n set: (value: T) => MaybeAsync<void>\n initialState: T\n readOptions?: AsyncComputedOptions\n asyncRead?: boolean\n debugging?: Partial<{\n log: {\n name: string\n writesOnly?: boolean\n readsOnly?: boolean\n logger?: (msg: string, ...args: any[]) => void\n }\n }>\n}\n\nexport type AsyncWritableComputedRef<T> = ComputedRef<T> & {\n update: AsyncWritableComputedOptions<T>['set']\n}\n\n/**\n * Allows async read/write from/to computed. Use `res.value` to read and `res.update` to write. If you only need\n * the computed to be read-only then use vueuse's `computedAsync`. If you only need async writes you can\n * disable async reads through the `asyncRead` param.\n * @param params\n */\nexport function writableAsyncComputed<T>(\n params: AsyncWritableComputedOptions<T>\n): AsyncWritableComputedRef<T> {\n const { get, initialState, readOptions, set, asyncRead = true, debugging } = params\n const logSettings = debugging?.log\n const getTrace = () => (new Error('Trace:').stack || '').substring(7)\n const logger = params.debugging?.log?.logger || console.debug\n\n const finalGet: typeof get =\n logSettings && !logSettings.writesOnly\n ? () => {\n const res = get()\n logger(`debugging: '${logSettings.name}' read`, res, getTrace())\n return res\n }\n : get\n\n const finalSet: typeof set =\n logSettings && !logSettings.readsOnly\n ? (newVal) => {\n logger(`debugging: '${logSettings.name}' written to`, newVal, getTrace())\n return set(newVal)\n }\n : set\n\n const readValue = asyncRead\n ? computedAsync(finalGet, initialState, readOptions)\n : computed(finalGet)\n\n const getter = computed(() => readValue.value) as AsyncWritableComputedRef<T>\n getter.update = finalSet\n\n return getter\n}\n\n/**\n * Build promise that can be resolved/rejected manually outside of the promise's execution scope\n */\nexport const buildManualPromise = <T>() => {\n let resolve: (value: T) => void\n let reject: (reason?: any) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n\n const resolveWrapper: typeof resolve = (...args) => resolve(...args)\n const rejectWrapper: typeof reject = (...args) => reject(...args)\n\n return { promise, resolve: resolveWrapper, reject: rejectWrapper }\n}\n","<script lang=\"ts\">\nenum Focus {\n /** Focus the first non-disabled item. */\n First,\n\n /** Focus the previous non-disabled item. */\n Previous,\n\n /** Focus the next non-disabled item. */\n Next,\n\n /** Focus the last non-disabled item. */\n Last,\n\n /** Focus a specific item based on the `id` of the item. */\n Specific,\n\n /** Focus no items at all. */\n Nothing\n}\nenum ComboboxStates {\n Open,\n Closed\n}\n</script>\n<template>\n <slot />\n</template>\n<script setup lang=\"ts\">\nimport type { Nullable, Optional } from '@speckle/shared'\nimport { getCurrentInstance, inject } from 'vue'\nimport type { ComponentInternalInstance, Ref } from 'vue'\n\n/**\n * Sort of hacky - we need to manipulate the @headlessui combobox state, but it can't be injected\n * from its parent component (Tags.vue). This being initialized inside of a slot of the combobox,\n * it has access to the context\n *\n * Also the context is inaccessible due to it being tied to a private symbol, so we need\n * to retrieve that a bit hackily too.\n */\n\n// Copied from headlessui\n\n\n\n\nconst instance = getCurrentInstance() as ComponentInternalInstance & {\n provides: Record<symbol | string, unknown>\n}\nconst provides = instance['provides']\nconst ctxKey = Object.getOwnPropertySymbols(provides).find(\n (s) => s.description === 'ComboboxContext'\n)\nif (!ctxKey) {\n console.error('FormTagsContextManager ctx key not found!')\n}\n\nconst state = inject(ctxKey || '__undefined') as Optional<{\n goToOption: (focus: Focus) => void\n openCombobox: () => void\n closeCombobox: () => void\n activeOptionIndex: Ref<Nullable<number>>\n selectActiveOption: () => void\n comboboxState: Ref<ComboboxStates>\n}>\n\nif (!state) {\n console.error('FormTagsContextManager ctx not found!')\n}\n\nconst goUp = () => {\n state?.goToOption(Focus.Previous)\n}\nconst goDown = () => {\n state?.goToOption(Focus.Next)\n}\nconst open = () => {\n if (!state) return\n state.openCombobox()\n}\nconst close = () => {\n state?.closeCombobox()\n}\nconst selectActive = () => {\n state?.selectActiveOption()\n}\nconst isOpen = () => state?.comboboxState.value === ComboboxStates.Open\n\ndefineExpose({ goUp, goDown, open, close, selectActive, isOpen })\n</script>\n","<template>\n <Combobox\n v-model=\"selectedItems\"\n as=\"div\"\n multiple\n clearable\n :class=\"[wrapperClasses]\"\n >\n <FormTagsContextManager ref=\"ctxManager\">\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n <div\n class=\"relative flex flex-wrap items-center space-x-1 px-2 py-1\"\n :class=\"inputWrapperClasses\"\n >\n <CommonBadge\n v-for=\"tag in selectedItems\"\n :key=\"tag\"\n :icon-left=\"!disabled ? XMarkIcon : undefined\"\n clickable-icon\n size=\"lg\"\n @click-icon=\"() => removeTag(tag)\"\n >\n {{ tag }}\n </CommonBadge>\n <input\n ref=\"inputEl\"\n v-model=\"query\"\n :disabled=\"disabled\"\n class=\"bg-transparent grow shrink border-0 focus:ring-0 p-0\"\n :class=\"[coreInputClasses, sizeClasses]\"\n style=\"flex-basis: 70px; min-width: 70px\"\n :placeholder=\"!selectedItems.length ? placeholder : undefined\"\n @input=\"onQueryInput\"\n @keydown.escape=\"onQueryEscape\"\n @keydown.enter.stop.prevent=\"onQueryInput($event, true)\"\n @keydown.tab=\"onQueryInput\"\n @keydown.backspace=\"onQueryBackspace\"\n @keydown.arrow-up=\"onQueryArrowUp\"\n @keydown.arrow-down=\"onQueryArrowDown\"\n @blur=\"isAutocompleteOpen = false\"\n />\n <a\n v-if=\"shouldShowClear\"\n title=\"Clear input\"\n class=\"absolute top-2 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-if=\"errorMessage\"\n :class=\"[\n 'pointer-events-none absolute top-[10px] right-0 flex items-center',\n shouldShowClear ? 'pr-8' : 'pr-2'\n ]\"\n >\n <ExclamationCircleIcon class=\"h-4 w-4 text-danger\" aria-hidden=\"true\" />\n </div>\n <div\n v-if=\"showRequired && !errorMessage\"\n class=\"pointer-events-none absolute top-[2px] text-4xl right-0 flex items-center text-danger opacity-50\"\n :class=\"shouldShowClear ? 'pr-8' : 'pr-2'\"\n >\n *\n </div>\n </div>\n <TransitionRoot\n leave=\"transition ease-in duration-100\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n class=\"relative px-0.5\"\n >\n <ComboboxOptions\n class=\"absolute top-1 max-h-60 w-full overflow-auto simple-scrollbar rounded-md bg-foundation-2 py-1 shadow label label--light outline outline-2 outline-primary-muted focus:outline-none\"\n >\n <div\n v-if=\"isAutocompleteLoading\"\n class=\"px-1\"\n :class=\"autocompleteItems.length ? 'mb-1' : ''\"\n >\n <CommonLoadingBar :loading=\"true\" />\n </div>\n <div v-if=\"!autocompleteItems.length && !isAutocompleteLoading\">\n <div class=\"text-foreground-2 text-center\">\n Press\n <strong>Enter</strong>\n to create tag ⚡\n </div>\n </div>\n <template v-if=\"autocompleteItems.length\">\n <ComboboxOption\n v-for=\"tag in autocompleteItems\"\n :key=\"tag\"\n v-slot=\"{ selected, active }\"\n as=\"template\"\n :value=\"tag\"\n >\n <li\n class=\"relative cursor-pointer select-none py-1.5 pl-3\"\n :class=\"{\n 'text-primary': active,\n 'text-foreground': !active\n }\"\n >\n <span\n class=\"block truncate\"\n :class=\"{ 'font-medium': selected, 'font-normal': !selected }\"\n >\n {{ tag }}\n </span>\n <span\n v-if=\"selected\"\n class=\"absolute inset-y-0 right-0 flex items-center pr-4\"\n :class=\"{ 'text-primary': active, 'text-foreground': !active }\"\n >\n <CheckIcon class=\"h-5 w-5\" aria-hidden=\"true\" />\n </span>\n </li>\n </ComboboxOption>\n </template>\n </ComboboxOptions>\n </TransitionRoot>\n <p v-if=\"helpTipId && !hideHelpTip\" :id=\"helpTipId\" :class=\"helpTipClasses\">\n {{ helpTip }}\n </p>\n </FormTagsContextManager>\n </Combobox>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, toRefs, watch, onMounted } from 'vue'\nimport {\n Combobox,\n ComboboxOptions,\n ComboboxOption,\n TransitionRoot\n} from '@headlessui/vue'\nimport { CheckIcon, XMarkIcon, ExclamationCircleIcon } from '@heroicons/vue/20/solid'\nimport { debounce, uniq } from 'lodash'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport type { RuleExpression } from 'vee-validate'\nimport type { MaybeAsync, Nullable } from '@speckle/shared'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\nimport FormTagsContextManager from '~~/src/components/form/tags/ContextManager.vue'\nimport { useFocus } from '@vueuse/core'\nimport CommonLoadingBar from '~~/src/components/common/loading/Bar.vue'\n\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\ntype Tag = string\nconst isInputEvent = (e: Event): e is InputEvent => e.type === 'input'\n\nconst emit = defineEmits([\"update:modelValue\", \"change\", \"clear\"])\n\nconst props = defineProps({\n name: null,\n help: null,\n label: null,\n showLabel: { type: Boolean },\n rules: null,\n validateOnMount: { type: Boolean },\n validateOnValueUpdate: { type: Boolean },\n autoFocus: { type: Boolean },\n showClear: { type: Boolean },\n showRequired: { type: Boolean },\n color: { default: 'page' },\n wrapperClasses: null,\n size: { default: 'base' },\n placeholder: null,\n disabled: { type: Boolean },\n useLabelInErrors: { type: Boolean, default: true },\n getAutocompleteItems: { type: Function },\n modelValue: null\n})\n\n// const localValue = defineModel<Tag[]>({ local: true })\nconst inputEl = ref(null as Nullable<HTMLInputElement>)\nconst { focused: isInputFocused } = useFocus(inputEl)\n\nconst ctxManager = ref(\n null as Nullable<{\n goUp: () => void\n goDown: () => void\n open: () => void\n close: () => void\n selectActive: () => void\n isOpen: () => boolean\n }>\n)\n\nconst {\n coreInputClasses,\n coreClasses,\n labelClasses,\n title,\n helpTip,\n helpTipId,\n hideHelpTip,\n helpTipClasses,\n errorMessage,\n clear,\n value\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl\n // options: {\n // customClear: () => (selectedItems.value = [])\n // }\n})\n\nconst autocompleteItems = ref([] as string[])\nconst isAutocompleteLoading = ref(false)\nconst isAutocompleteOpen = ref(false)\nconst query = ref('')\n\nconst selectedItems = computed({\n get: () => value.value || [],\n set: (newVal) => {\n value.value = uniq(newVal).filter((t) => !!t.length)\n }\n})\n\nconst sizeClasses = computed((): string => {\n switch (props.size) {\n case 'sm':\n return 'h-6'\n case 'lg':\n return 'h-10'\n case 'xl':\n return 'h-14'\n case 'base':\n default:\n return 'h-8'\n }\n})\n\nconst shouldShowClear = computed(() => props.showClear && !!selectedItems.value.length)\n\nconst inputWrapperClasses = computed(() => {\n const classParts: string[] = [\n coreClasses.value,\n props.disabled\n ? 'cursor-not-allowed !bg-foundation-disabled !text-disabled-muted'\n : ''\n ]\n\n if (shouldShowClear.value && (errorMessage.value || props.showRequired)) {\n classParts.push('pr-14')\n } else if (shouldShowClear.value || errorMessage.value || props.showRequired) {\n classParts.push('pr-8')\n }\n\n if (errorMessage.value) {\n classParts.push('border-2 border-danger text-danger-darker')\n if (isInputFocused.value) {\n classParts.push('ring-1 ring-danger')\n }\n } else {\n classParts.push('border-2 border-transparent')\n if (isInputFocused.value) {\n classParts.push('ring-2 ring-outline-2')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst removeTag = (tag: Tag) => {\n if (props.disabled) return\n\n const idx = selectedItems.value.indexOf(tag)\n if (idx !== -1) {\n const newSelected = selectedItems.value.slice()\n newSelected.splice(idx, 1)\n\n selectedItems.value = newSelected\n }\n}\n\nconst onQueryEscape = () => {\n inputEl.value?.blur()\n isAutocompleteOpen.value = false\n}\n\nconst onQueryBackspace = (e: KeyboardEvent) => {\n if (e.key !== 'Backspace') return\n if (query.value.length) return\n\n // Clear last tag\n const newTags = selectedItems.value.slice()\n newTags.pop()\n selectedItems.value = newTags\n isAutocompleteOpen.value = false\n}\n\nconst onQueryArrowUp = () => {\n if (ctxManager.value?.isOpen()) {\n ctxManager.value?.goUp()\n } else {\n ctxManager.value?.open()\n }\n}\n\nconst onQueryArrowDown = () => {\n if (ctxManager.value?.isOpen()) {\n ctxManager.value?.goDown()\n } else {\n ctxManager.value?.open()\n }\n}\n\nconst resolveAutocompleteItems = async () => {\n if (!props.getAutocompleteItems) return\n\n isAutocompleteLoading.value = true\n autocompleteItems.value = await Promise.resolve(\n props.getAutocompleteItems(query.value)\n )\n isAutocompleteLoading.value = false\n}\nconst debouncedResolve = debounce(resolveAutocompleteItems, 1000)\nconst debouncedResolveAndMarkLoading = () => {\n isAutocompleteLoading.value = true\n debouncedResolve()\n}\n\nconst onQueryInput = (e: Event, forceCreateFromInput?: boolean) => {\n const isAddingTag = isInputEvent(e)\n ? e.data === ' ' || e.data === ',' || e.data === ';'\n : true\n\n if (isAddingTag) {\n let selected = false\n if (\n ctxManager.value?.isOpen() &&\n autocompleteItems.value.length &&\n !forceCreateFromInput\n ) {\n // Add from opened autocomplete panel\n ctxManager.value?.selectActive()\n selected = true\n } else {\n // Add from query\n const newTag = query.value\n .trim()\n .substring(0, query.value.length - (isInputEvent(e) ? 1 : 0))\n\n const tagExists = selectedItems.value.includes(newTag)\n if (newTag.length > 0 && !tagExists) {\n selectedItems.value = [...selectedItems.value, newTag]\n selected = true\n }\n }\n\n if (selected) {\n query.value = ''\n isAutocompleteOpen.value = false\n }\n } else {\n isAutocompleteOpen.value = !!query.value.length\n }\n}\n\nwatch(isAutocompleteOpen, (newIsOpen, oldIsOpen) => {\n if (newIsOpen && !oldIsOpen) {\n if (props.getAutocompleteItems) ctxManager.value?.open()\n } else if (!newIsOpen && oldIsOpen) {\n ctxManager.value?.close()\n }\n})\n\nwatch(query, () => {\n debouncedResolveAndMarkLoading()\n})\n\n// // syncing value w/ vee-validate internal state\n// watch(\n// selectedItems,\n// (newVal) => {\n// value.value = newVal.slice()\n// },\n// { deep: true, immediate: true }\n// )\n\nonMounted(() => {\n resolveAutocompleteItems()\n})\n\ndefineExpose({ resolveAutocompleteItems })\n</script>\n","import { computed } from 'vue'\nimport type { ToRefs } from 'vue'\n\nexport type AvatarUser = {\n name: string\n avatar?: string | null\n}\n\nexport type AvatarUserWithId = AvatarUser & { id: string }\n\nexport type UserAvatarSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | 'xxl' | 'editable'\n\nexport function useAvatarSizeClasses(params: {\n props: ToRefs<{\n size?: UserAvatarSize\n }>\n}) {\n const { props } = params\n\n const heightClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'h-5'\n case 'sm':\n return 'h-6'\n case 'lg':\n return 'h-10'\n case 'xl':\n return 'h-14'\n case 'xxl':\n return 'h-32'\n case 'editable':\n return 'h-60'\n case 'base':\n default:\n return 'h-8'\n }\n })\n\n const widthClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'w-5'\n case 'sm':\n return 'w-6'\n case 'lg':\n return 'w-10'\n case 'xl':\n return 'w-14'\n case 'xxl':\n return 'w-32'\n case 'editable':\n return 'w-60'\n case 'base':\n default:\n return 'w-8'\n }\n })\n\n const textClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'text-tiny'\n case 'sm':\n return 'text-xs'\n case 'lg':\n return 'text-md'\n case 'xl':\n return 'text-2xl'\n case 'xxl':\n return 'text-3xl'\n case 'editable':\n return 'h1'\n case 'base':\n default:\n return 'text-sm'\n }\n })\n\n const iconClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case 'xs':\n return 'w-3 h-3'\n case 'sm':\n return 'w-3 h-3'\n case 'lg':\n return 'w-5 h-5'\n case 'xl':\n return 'w-8 h-8'\n case 'xxl':\n return 'w-10 h-10'\n case 'editable':\n return 'w-20 h-20'\n case 'base':\n default:\n return 'w-4 h-4'\n }\n })\n\n const sizeClasses = computed(\n () => `${widthClasses.value} ${heightClasses.value} ${textClasses.value}`\n )\n\n return { heightClasses, widthClasses, sizeClasses, iconClasses }\n}\n","<template>\n <div\n :class=\"[\n 'text-foreground-on-primary flex shrink-0 items-center justify-center overflow-hidden rounded-full font-semibold uppercase transition',\n sizeClasses,\n bgClasses,\n borderClasses,\n hoverClasses,\n activeClasses\n ]\"\n >\n <slot>\n <div\n v-if=\"user?.avatar\"\n class=\"h-full w-full bg-cover bg-center bg-no-repeat\"\n :style=\"{ backgroundImage: `url('${user.avatar}')` }\"\n />\n <div\n v-else-if=\"initials\"\n class=\"flex h-full w-full select-none items-center justify-center\"\n >\n {{ initials }}\n </div>\n <div v-else><UserCircleIcon :class=\"iconClasses\" /></div>\n </slot>\n <slot name=\"absolute-anchor\" />\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { UserCircleIcon } from '@heroicons/vue/24/solid'\nimport type { MaybeNullOrUndefined } from '@speckle/shared'\nimport { computed, toRefs } from 'vue'\nimport { useAvatarSizeClasses } from '~~/src/composables/user/avatar'\nimport type { AvatarUser, UserAvatarSize } from '~~/src/composables/user/avatar'\n\nconst props = defineProps({\n user: { default: null },\n size: { default: 'base' },\n hoverEffect: { type: Boolean, default: false },\n active: { type: Boolean },\n noBorder: { type: Boolean },\n noBg: { type: Boolean }\n})\n\nconst { sizeClasses, iconClasses } = useAvatarSizeClasses({ props: toRefs(props) })\n\nconst initials = computed(() => {\n if (!props.user?.name.length) return\n const parts = props.user.name.split(' ')\n const firstLetter = parts[0]?.[0] || ''\n const secondLetter = parts[1]?.[0] || ''\n\n if (props.size === 'sm' || props.size === 'xs') return firstLetter\n return firstLetter + secondLetter\n})\n\nconst borderClasses = computed(() => {\n if (props.noBorder) return ''\n return 'border-2 border-foundation'\n})\n\nconst bgClasses = computed(() => {\n if (props.noBg) return ''\n return 'bg-primary'\n})\n\nconst hoverClasses = computed(() => {\n if (props.hoverEffect)\n return 'hover:border-primary focus:border-primary active:scale-95'\n return ''\n})\n\nconst activeClasses = computed(() => {\n if (props.active) return 'border-primary'\n return ''\n})\n</script>\n","<template>\n <div ref=\"elementToWatchForChanges\" :class=\"`flex ${overlap ? '-space-x-2' : ''}`\">\n <div\n ref=\"itemContainer\"\n :class=\"`flex flex-wrap overflow-hidden ${\n overlap ? '-space-x-2 ' : ''\n } ${heightClasses}`\"\n >\n <UserAvatar\n v-for=\"(user, i) in items\"\n :key=\"user.id || i\"\n :user=\"user\"\n :size=\"size\"\n />\n </div>\n <UserAvatar v-if=\"finalHiddenItemCount\" :size=\"size\">\n +{{ finalHiddenItemCount }}\n </UserAvatar>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref, toRefs } from 'vue'\nimport UserAvatar from '~~/src/components/user/Avatar.vue'\nimport { useWrappingContainerHiddenCount } from '~~/src/composables/layout/resize'\nimport { useAvatarSizeClasses } from '~~/src/composables/user/avatar'\nimport type { UserAvatarSize, AvatarUserWithId } from '~~/src/composables/user/avatar'\n\nconst props = defineProps({\n users: { default: () => [] },\n overlap: { type: Boolean, default: true },\n size: { default: 'base' },\n maxCount: { default: undefined }\n})\n\nconst elementToWatchForChanges = ref(null as Nullable<HTMLElement>)\nconst itemContainer = ref(null as Nullable<HTMLElement>)\n\nconst { hiddenItemCount } = useWrappingContainerHiddenCount({\n elementToWatchForChanges,\n itemContainer,\n trackResize: true,\n trackMutations: true\n})\n\nconst { heightClasses } = useAvatarSizeClasses({ props: toRefs(props) })\n\nconst maxCountHiddenItemCount = computed(() => {\n if (!props.maxCount) return 0\n return Math.max(props.users.length - props.maxCount, 0)\n})\n\nconst finalHiddenItemCount = computed(\n () => hiddenItemCount.value + maxCountHiddenItemCount.value\n)\n\nconst items = computed(() =>\n props.maxCount ? props.users.slice(0, props.maxCount) : props.users\n)\n</script>\n","<template>\n <ArrowPathIcon :class=\"iconClasses\" />\n</template>\n<script setup lang=\"ts\">\nimport { ArrowPathIcon } from '@heroicons/vue/24/solid'\nimport { computed } from 'vue'\n\ntype Size = 'base' | 'sm' | 'lg'\n\nconst props = defineProps({\n loading: { type: Boolean, default: true },\n size: { default: 'base' }\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['text-primary transition-all animate-spin']\n classParts.push(props.loading ? 'opacity-100' : 'opacity-0')\n\n switch (props.size) {\n case 'base':\n classParts.push('h-8 w-8')\n break\n case 'sm':\n classParts.push('h-5 w-5')\n break\n case 'lg':\n classParts.push('h-12 w-12')\n break\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <div class=\"flex flex-col items-center space-y-2\">\n <LazyUserAvatarEditor\n v-if=\"editMode\"\n :user=\"modelAsUser\"\n :disabled=\"disabled\"\n :size=\"size\"\n @cancel=\"editMode = false\"\n @save=\"onSave\"\n />\n <div v-else class=\"relative group\">\n <UserAvatar :user=\"modelAsUser\" :size=\"size\" />\n <div\n class=\"opacity-0 transition-all absolute group-hover:opacity-100 inset-0 flex items-end justify-center bottom-4\"\n >\n <FormButton :disabled=\"disabled\" color=\"secondary\" @click=\"editMode = true\">\n Change\n </FormButton>\n </div>\n </div>\n <div v-if=\"errorMessage\" class=\"w-full text-center text-danger text-sm\">\n {{ errorMessage }}\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'\nimport { computed, defineAsyncComponent } from 'vue'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport UserAvatar from '~~/src/components/user/Avatar.vue'\nimport type { AvatarUser, UserAvatarSize } from '~~/src/composables/user/avatar'\nimport CommonLoadingIcon from '~~/src/components/common/loading/Icon.vue'\nimport { useField } from 'vee-validate'\nimport type { RuleExpression } from 'vee-validate'\n\ntype ModelType = MaybeNullOrUndefined<string>\n\nconst LazyUserAvatarEditor = defineAsyncComponent({\n loader: () => import('~~/src/components/user/AvatarEditor.vue'),\n loadingComponent: CommonLoadingIcon,\n delay: 100\n})\n\nconst emit = defineEmits([\"save\", \"update:modelValue\"])\n\nconst props = defineProps({\n modelValue: null,\n placeholder: null,\n name: null,\n rules: null,\n validateOnMount: { type: Boolean },\n validateOnValueUpdate: { type: Boolean },\n disabled: { type: Boolean },\n size: null\n})\n\nconst { value, errorMessage } = useField<ModelType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n initialValue: props.modelValue || undefined\n})\n\nconst editMode = defineModel<boolean>('editMode', { local: true })\n\nconst modelAsUser = computed(\n (): AvatarUser => ({\n avatar: value.value,\n name: props.placeholder\n })\n)\n\nconst onSave = (newUrl: Nullable<string>) => {\n value.value = newUrl\n emit('save', newUrl)\n}\n\nconst open = () => (editMode.value = true)\nconst close = () => (editMode.value = false)\n\ndefineExpose({ open, close })\n</script>\n","/**\n * Base ObjectLoader error\n */\nexport abstract class BaseError extends Error {\n /**\n * Default message if none is passed\n */\n static defaultMessage = 'Unexpected error occurred'\n\n constructor(message?: string, options?: ErrorOptions) {\n message ||= new.target.defaultMessage\n super(message, options)\n }\n}\n\n/**\n * Throw these in execution branches that should never occur unless if there's a bug\n */\nexport class LogicError extends BaseError {\n static defaultMessage = 'An unexpected logic error occurred!'\n}\n\nexport class UninitializedResourceAccessError extends BaseError {\n static defaultMessage = 'Attempting to access an uninitialized resource'\n}\n\nexport class ComposableInvokedOutOfScopeError extends BaseError {\n static defaultMessage =\n 'getCurrentInstance() returned null. Method must be called at the top of a setup function'\n}\n\n/**\n * Throw this when something that's only supported during CSR is invoked during SSR or vice versa\n */\nexport class UnsupportedEnvironmentError extends BaseError {\n static defaultMessage =\n 'Operation not supported in current (server or client) environment'\n}\n","import { difference, intersection } from 'lodash'\nimport { md5 } from '@speckle/shared'\nimport type { Nullable } from '@speckle/shared'\nimport { BaseError } from '~~/src/helpers/common/error'\n\nexport type FileTypeSpecifier = UniqueFileTypeSpecifier | `.${string}`\n\nexport enum UniqueFileTypeSpecifier {\n AnyAudio = 'audio/*',\n AnyVideo = 'video/*',\n AnyImage = 'image/*'\n}\n\n/**\n * Validate if file has the allowed type. While we could also test for MIME types\n * not in UniqueFileTypeSpecifier, this function is meant to be equivalent to the\n * 'accept' attribute, which only allows for extensions or UniqueFileTypeSpecifier\n * values.\n * @param file\n * @param allowedTypes The file must have one of these types\n * @returns True if valid, Error object if not\n */\nexport function validateFileType(\n file: File,\n allowedTypes: FileTypeSpecifier[]\n): true | Error {\n // Check one of the unique file type specifiers first\n const allowedUniqueTypes = intersection(\n Object.values(UniqueFileTypeSpecifier),\n allowedTypes\n )\n for (const allowedUniqueType of allowedUniqueTypes) {\n switch (allowedUniqueType) {\n case UniqueFileTypeSpecifier.AnyAudio:\n if (file.type.startsWith('audio')) return true\n break\n case UniqueFileTypeSpecifier.AnyImage:\n if (file.type.startsWith('image')) return true\n break\n case UniqueFileTypeSpecifier.AnyVideo:\n if (file.type.startsWith('video')) return true\n break\n }\n }\n\n // Check file extensions\n const allowedExtensions = difference(allowedTypes, allowedUniqueTypes)\n const fileExt = resolveFileExtension(file.name)\n if (!fileExt) return new MissingFileExtensionError()\n\n for (const allowedExtension of allowedExtensions) {\n if (allowedExtension.toLowerCase() === fileExt.toLowerCase()) return true\n }\n\n return new ForbiddenFileTypeError()\n}\n\n/**\n * Resolve file extension (with leading dot)\n */\nexport function resolveFileExtension(fileName: string): Nullable<FileTypeSpecifier> {\n const ext = fileName.split('.').pop() || null\n return ext ? `.${ext}` : null\n}\n\n/**\n * Check if string is a FileTypeSpecifier\n */\nexport function isFileTypeSpecifier(type: string): type is FileTypeSpecifier {\n return (\n type.startsWith('.') ||\n Object.values(UniqueFileTypeSpecifier as Record<string, string>).includes(type)\n )\n}\n\n/**\n * Create a human readable file size string from the numeric size in bytes\n */\nexport function prettyFileSize(sizeInBytes: number): string {\n const removeTrailingZeroes = (fileSize: number) =>\n parseFloat(fileSize.toFixed(2)).toString()\n\n if (sizeInBytes < 1024) {\n return `${sizeInBytes}bytes`\n }\n\n const kbSize = sizeInBytes / 1024\n if (kbSize < 1024) {\n return `${removeTrailingZeroes(kbSize)}KB`\n }\n\n const mbSize = kbSize / 1024\n if (mbSize < 1024) {\n return `${removeTrailingZeroes(mbSize)}MB`\n }\n\n const gbSize = mbSize / 1024\n return `${removeTrailingZeroes(gbSize)}GB`\n}\n\n/**\n * Generate an ID that uniquely identifies a specific file. The same file\n * will always have the same ID.\n */\nexport function generateFileId(file: File): string {\n const importantData = {\n name: file.name,\n lastModified: file.lastModified,\n size: file.size,\n type: file.type\n }\n\n return md5(JSON.stringify(importantData))\n}\n\nexport class MissingFileExtensionError extends BaseError {\n static defaultMessage = 'The selected file has a missing extension'\n}\n\nexport class ForbiddenFileTypeError extends BaseError {\n static defaultMessage = 'The selected file type is forbidden'\n}\n","import type { MaybeRef } from '@vueuse/core'\nimport type { MaybeNullOrUndefined, Nullable, Optional } from '@speckle/shared'\nimport {\n generateFileId,\n isFileTypeSpecifier,\n prettyFileSize,\n validateFileType\n} from '~~/src/helpers/form/file'\nimport type { FileTypeSpecifier } from '~~/src/helpers/form/file'\nimport { computed, unref } from 'vue'\nimport type { CSSProperties } from 'vue'\nimport { BaseError } from '~~/src/lib'\n\n/**\n * A file, as emitted out from FileUploadZone\n */\nexport interface UploadableFileItem {\n file: File\n error: Nullable<Error>\n /**\n * You can use this ID to check for File equality\n */\n id: string\n}\n\nexport enum BlobUploadStatus {\n Success = 1,\n Failure = 2\n}\n\nexport type BlobPostResultItem = {\n blobId?: string\n fileName?: string\n fileSize?: number\n formKey: string\n /**\n * Success = 1, Failure = 2\n */\n uploadStatus: number\n uploadError: string\n}\n\nexport interface UploadFileItem extends UploadableFileItem {\n /**\n * Progress between 0 and 100\n */\n progress: number\n\n /**\n * When upload has finished this contains a BlobPostResultItem\n */\n result: Optional<BlobPostResultItem>\n\n /**\n * When a blob gets assigned to a resource, it should count as in use, and this will\n * prevent it from being deleted as junk\n */\n inUse?: boolean\n}\n\nfunction buildFileTypeSpecifiers(\n accept: Optional<string>\n): Optional<FileTypeSpecifier[]> {\n if (!accept) return undefined\n const specifiers = accept\n .split(',')\n .map((s) => (isFileTypeSpecifier(s) ? s : null))\n .filter((s): s is FileTypeSpecifier => s !== null)\n\n return specifiers.length ? specifiers : undefined\n}\n\nexport function usePrepareUploadableFiles(params: {\n disabled?: MaybeRef<Optional<boolean>>\n accept?: MaybeRef<Optional<string>>\n multiple?: MaybeRef<Optional<boolean>>\n countLimit?: MaybeRef<Optional<number>>\n sizeLimit: MaybeRef<number>\n}) {\n const { disabled, accept, multiple, sizeLimit, countLimit } = params\n\n const fileTypeSpecifiers = computed(() => buildFileTypeSpecifiers(unref(accept)))\n\n const handleFiles = (files: File[]): UploadableFileItem[] => {\n const results: UploadableFileItem[] = []\n const allowedTypes = fileTypeSpecifiers.value\n\n for (const file of files) {\n const id = generateFileId(file)\n const finalCountLimit = !unref(multiple) ? 1 : unref(countLimit)\n\n // skip file, if it's selected twice somehow\n if (results.find((r) => r.id === id)) continue\n\n // Only allow a single file if !multiple\n if (finalCountLimit && results.length >= finalCountLimit) {\n break\n }\n\n if (allowedTypes) {\n const validationResult = validateFileType(file, allowedTypes)\n if (validationResult instanceof Error) {\n results.push({\n file,\n id,\n error: validationResult\n })\n continue\n }\n }\n\n if (file.size > unref(sizeLimit)) {\n results.push({\n file,\n id,\n error: new FileTooLargeError(\n `The selected file's size (${prettyFileSize(\n file.size\n )}) is too big (over ${prettyFileSize(unref(sizeLimit))})`\n )\n })\n continue\n }\n\n results.push({ file, id, error: null })\n }\n\n return results\n }\n\n return {\n /**\n * Validate incoming files and build UploadableFileItem structs out of them\n */\n buildUploadableFiles: (files: File[]) => {\n if (unref(disabled || false)) return\n return handleFiles(files)\n }\n }\n}\n\nclass FileTooLargeError extends BaseError {\n static defaultMessage = \"The selected file's size is too large\"\n}\n\nexport function useFileUploadProgressCore(params: {\n item: MaybeRef<MaybeNullOrUndefined<UploadFileItem>>\n}) {\n const errorMessage = computed(() => {\n const item = unref(params.item)\n if (!item) return null\n\n const itemError = item.error\n if (itemError) return itemError.message\n\n const uploadError = item.result?.uploadError\n if (uploadError) return uploadError\n\n return null\n })\n\n const progressBarColorClass = computed(() => {\n const item = unref(params.item)\n if (errorMessage.value) return 'bg-danger'\n if (item && item.progress >= 100) return 'bg-success'\n return 'bg-primary'\n })\n\n const progressBarClasses = computed(() => {\n return ['h-1', progressBarColorClass.value].join(' ')\n })\n\n const progressBarStyle = computed((): CSSProperties => {\n const item = unref(params.item)\n return {\n width: `${item ? item.progress : 0}%`\n }\n })\n\n return { errorMessage, progressBarClasses, progressBarStyle }\n}\n","<!-- eslint-disable vuejs-accessibility/form-control-has-label -->\n<template>\n <div ref=\"fileUploadZone\" class=\"file-upload-zone\">\n <slot\n :is-dragging-files=\"isOverDropZone\"\n :open-file-picker=\"triggerPicker\"\n :activator-on=\"{ click: triggerPicker }\"\n />\n <input\n ref=\"fileInput\"\n type=\"file\"\n class=\"hidden\"\n :accept=\"accept\"\n :multiple=\"multiple\"\n @click.stop\n @change=\"onInputChange\"\n />\n </div>\n</template>\n<script setup lang=\"ts\">\n/* eslint-disable vue/require-default-prop */\nimport type { Nullable } from '@speckle/shared'\nimport { useDropZone } from '@vueuse/core'\nimport { computed, ref } from 'vue'\nimport { usePrepareUploadableFiles } from '~~/src/composables/form/fileUpload'\nimport type { UploadableFileItem } from '~~/src/composables/form/fileUpload'\n\nconst emit = defineEmits([\"files-selected\"])\n\nconst props = defineProps({\n accept: null,\n multiple: { type: Boolean },\n sizeLimit: { default: 1024 * 1024 * 100 },\n countLimit: null,\n disabled: { type: Boolean }\n})\n\nconst fileUploadZone = ref(null as Nullable<HTMLDivElement>)\nconst fileInput = ref(null as Nullable<HTMLInputElement>)\n\nconst { buildUploadableFiles } = usePrepareUploadableFiles({\n sizeLimit: computed(() => props.sizeLimit),\n countLimit: computed(() => props.countLimit),\n accept: computed(() => props.accept),\n multiple: computed(() => props.multiple),\n disabled: computed(() => props.disabled)\n})\nconst handleIncomingFiles = (files: File[]) => {\n const fileItems = buildUploadableFiles(files)\n if (!fileItems?.length) return\n emit('files-selected', { files: fileItems })\n}\n\nconst { isOverDropZone } = useDropZone(fileUploadZone, (files) => {\n if (!files?.length) return\n handleIncomingFiles(files)\n})\n\nconst onInputChange = () => {\n const input = fileInput.value\n if (!input) return\n\n const files = [...(input.files || [])]\n input.value = '' // Resetting value\n\n if (!files.length) return\n handleIncomingFiles(files)\n}\n\nconst triggerPicker = () => {\n fileInput.value?.click()\n}\n\ndefineExpose({\n triggerPicker\n})\n</script>\n"],"names":["emit","__emit","props","__props","NuxtLink","resolveDynamicComponent","RouterLink","linkComponent","computed","isObjectLike","buttonType","isDisabled","finalLeftIcon","ArrowPathIcon","bgAndBorderClasses","classParts","foregroundClasses","hasCustomTextColor","roundedClasses","ringClasses","sizeClasses","paddingClasses","generalClasses","decoratorClasses","buttonClasses","isLinkOrText","iconClasses","onClick","e","ToastNotificationType","ToastNotificationType2","isTitleOnly","_a","_b","dismiss","onCtaClick","_c","KEYBOARD_CLICK_CHAR","keyboardClick","cb","badgeColorClasses","badgeDotIconColorClasses","badgeClasses","dotClasses","onIconClick","junkVariable","markClassesUsed","classes","TailwindBreakpoints","useStepsInternals","params","modelValue","steps","orientation","goVerticalBelow","nonInteractive","stepsPadding","finalOrientation","value","clamp","newVal","getStepDisplayValue","step","isCurrentStep","isFinishedStep","switchStep","newStep","stepObj","listClasses","paddingHorizontal","paddingVertical","linkClasses","toRefs","labelClasses","leftMargin","extraListClasses","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_4","_sfc_render","_ctx","_cache","_hoisted_3","isAnimating","ref","mousePosition","isClicked","animationDuration","isMouseVisible","dynamicSlots","delay","action","wait","toggleSlotVisibility","slotToToggle","slot","handleAction","onMounted","onBeforeUnmount","computedClasses","generateRandomId","prefix","nanoid","checkboxValue","coreChecked","errorMessage","handleChange","coreValue","useField","title","descriptionText","descriptionId","descriptionClasses","implicitId","finalId","onChange","newModelValue","newCoreValue","shouldBeChecked","isCoreChecked","radioValue","useTextInputCore","inputEl","options","error","unref","coreInputClasses","coreClasses","color","internalHelpTipId","base","hideHelpTip","helpTip","hasHelpTip","helpTipId","helpTipClasses","focus","clear","isArray","inputElement","__expose","slots","useSlots","leadingIconClasses","hasLeadingIcon","VALID_HTTP_URL","VALID_EMAIL","isEmail","val","isOneOrMultipleEmails","i","isRequired","isString","isSameAs","otherFieldName","otherFieldDisplayName","meta","isStringOfLength","minLength","maxLength","isNullOrUndefined","isUndefined","stringContains","match","message","isUrl","isItemSelected","useWrappingContainerHiddenCount","skipCalculation","elementToWatchForChanges","itemContainer","trackResize","trackMutations","hiddenItemCount","recalculate","target","avatarElements","visibleCount","totalCount","firstElOffsetTop","avatarEl","offsetTop","useResizeObserver","useMutationObserver","useFormSelectChildInternals","dynamicVisibility","selectedValue","currentValue","isArrayValue","v","isObjectLikeType","isMounted","useMounted","searchInput","menuEl","listboxButton","searchValue","currentItems","isAsyncLoading","forceUpdateKey","listboxButtonBounding","useElementBounding","useIntersectionObserver","isIntersecting","renderClearButton","buttonsWrapperClasses","commonButtonClasses","clearButtonClasses","hasValueSelected","hasSearch","isAsyncSearchMode","wrappedValue","finalValue","currentVal","itemKey","clearValue","finalItems","searchVal","listboxOptionsClasses","listboxOptionsStyle","style","top","left","width","height","simpleDisplayText","triggerSearch","debouncedSearch","debounce","listboxOptionClasses","active","disabled","hideCheckmarks","watch","newItems","hiddenSelectedItemCount","isMultiItemArrayValue","firstItem","searchFilterPredicate","search","deselectItem","item","enabled","_useModel","copy","useClipboard","copied","handleCopy","selectAllText","event","textElement","selection","range","ModifierKeys","clientOs","getClientOperatingSystem","ModifierKeyTitles","OperatingSystem","getKeyboardShortcutTitle","keys","isModifierKey","k","onKeyboardShortcut","modifiers","args","onKeyDown","isAltOrOpt","isCtrlOrCmd","isShift","modifier","useFormCheckboxModel","model","isChecked","scrolledFromTop","scrolledToBottom","isForm","hasButtons","hasTitle","open","maxWidthWeight","widthClasses","onClose","onScroll","throttle","scrollTop","offsetHeight","scrollHeight","content","contentHeight","isExpanded","backgroundClass","titleClasses","toggleExpansion","nextTick","panelClasses","GridListToggleValue","ThrottleOrDebounce","ThrottleOrDebounce2","HorizontalDirection","HorizontalDirection2","useWindowResizeHandler","handler","isClient","throttleOrDebounce","finalHandler","useOnBeforeWindowUnload","useResponsiveHorizontalDirectionCalculation","el","defaultDirection","direction","stopUpdatesBelowWidth","element","recalculateDirection","rect","showOnLeftSide","showOnRightSide","menuItems","menuDirection","menuButton","isOpenInternally","finalOpen","buildButtonClassses","chooseItem","toggle","processOpen","isOpen","oldVal","shouldBeOpen","activeItemId","activeItem","onTabClick","buttonContainer","activeItemRef","id","parent","b","borderStyle","setActiveItem","paddingRightStyle","buttonCount","padding","rowsWrapperClasses","getHeaderClasses","column","c","getClasses","colIndex","columnClass","handleRowClick","wrapper","initializeLoader","int","secondarySlotPaddingClasses","defaultSlotPaddingClasses","hasDescription","icon","InformationCircleIcon","ExclamationCircleIcon","XCircleIcon","CheckCircleIcon","containerClasses","subcontainerClasses","mainContentContainerClasses","descriptionWrapperClasses","actionsContainerClasses","hasDescriptionAndActions","textClasses","actionSize","writableAsyncComputed","get","initialState","readOptions","set","asyncRead","debugging","logSettings","getTrace","logger","finalGet","res","finalSet","readValue","computedAsync","getter","buildManualPromise","resolve","reject","rej","provides","getCurrentInstance","ctxKey","s","state","inject","isInputEvent","isInputFocused","useFocus","ctxManager","autocompleteItems","isAutocompleteLoading","isAutocompleteOpen","query","selectedItems","uniq","t","shouldShowClear","inputWrapperClasses","removeTag","tag","idx","newSelected","onQueryEscape","onQueryBackspace","newTags","onQueryArrowUp","onQueryArrowDown","resolveAutocompleteItems","debouncedResolve","debouncedResolveAndMarkLoading","onQueryInput","forceCreateFromInput","selected","newTag","tagExists","newIsOpen","oldIsOpen","useAvatarSizeClasses","heightClasses","initials","parts","firstLetter","secondLetter","borderClasses","bgClasses","hoverClasses","activeClasses","maxCountHiddenItemCount","finalHiddenItemCount","items","LazyUserAvatarEditor","defineAsyncComponent","CommonLoadingIcon","editMode","modelAsUser","onSave","newUrl","BaseError","__publicField","LogicError","UninitializedResourceAccessError","ComposableInvokedOutOfScopeError","UnsupportedEnvironmentError","UniqueFileTypeSpecifier","validateFileType","file","allowedTypes","allowedUniqueTypes","intersection","allowedUniqueType","allowedExtensions","difference","fileExt","resolveFileExtension","MissingFileExtensionError","allowedExtension","ForbiddenFileTypeError","fileName","ext","isFileTypeSpecifier","type","prettyFileSize","sizeInBytes","removeTrailingZeroes","fileSize","kbSize","mbSize","gbSize","generateFileId","importantData","md5","BlobUploadStatus","buildFileTypeSpecifiers","accept","specifiers","usePrepareUploadableFiles","multiple","sizeLimit","countLimit","fileTypeSpecifiers","handleFiles","files","results","finalCountLimit","r","validationResult","FileTooLargeError","fileUploadZone","fileInput","buildUploadableFiles","handleIncomingFiles","fileItems","isOverDropZone","useDropZone","onInputChange","input","triggerPicker"],"mappings":"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"}