@speckle/ui-components 2.23.12 → 2.23.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/components/form/RadioGroup.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/common/loading/Bar.vue","../src/components/form/select/Base.vue","../src/components/form/select/SourceApps.vue","../src/components/form/select/Badges.vue","../src/components/form/select/Multi.vue","../src/components/form/Switch.vue","../src/components/form/ClipboardInput.vue","../src/components/form/CodeInput.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","../node_modules/lodash-es/_freeGlobal.js","../node_modules/lodash-es/_root.js","../node_modules/lodash-es/_Symbol.js","../node_modules/lodash-es/_getRawTag.js","../node_modules/lodash-es/_objectToString.js","../node_modules/lodash-es/_baseGetTag.js","../node_modules/lodash-es/isObjectLike.js","../node_modules/lodash-es/isSymbol.js","../node_modules/lodash-es/_trimmedEndIndex.js","../node_modules/lodash-es/_baseTrim.js","../node_modules/lodash-es/isObject.js","../node_modules/lodash-es/toNumber.js","../node_modules/lodash-es/now.js","../node_modules/lodash-es/debounce.js","../node_modules/lodash-es/throttle.js","../src/components/layout/tabs/Horizontal.vue","../src/components/layout/tabs/Vertical.vue","../src/components/layout/Table.vue","../src/components/InfiniteLoading.vue","../src/components/layout/Panel.vue","../src/components/layout/sidebar/Sidebar.vue","../src/components/layout/sidebar/menu/Menu.vue","../src/components/global/icon/Plus.vue","../src/components/global/icon/Edit.vue","../src/components/global/icon/ArrowFilled.vue","../src/components/layout/sidebar/menu/group/Group.vue","../src/components/layout/sidebar/menu/group/Item.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","../src/directives/accessibility.ts","../src/components/common/ProgressBar.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 :style=\"\n color !== 'subtle' && !text\n ? `box-shadow: -1px 1px 4px 0px #0000000a inset; box-shadow: 0px 2px 2px 0px #0000000d;`\n : ''\n \"\n @click=\"onClick\"\n >\n <Component :is=\"finalLeftIcon\" v-if=\"finalLeftIcon\" :class=\"iconClasses\" />\n <slot v-if=\"!hideText\">Button</slot>\n <Component :is=\"iconRight\" v-if=\"iconRight || !loading\" :class=\"iconClasses\" />\n </Component>\n</template>\n<script setup lang=\"ts\">\nimport { isObjectLike } from 'lodash'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\nimport { computed, resolveDynamicComponent } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport type { FormButtonStyle, FormButtonSize } from '~~/src/helpers/form/button'\nimport { CommonLoadingIcon } from '~~/src/lib'\n\nconst emit = defineEmits<{\n /**\n * Emit MouseEvent on click\n */\n (e: 'click', val: MouseEvent): void\n}>()\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?: string\n /**\n * Choose from one of 3 button sizes\n */\n size?: FormButtonSize\n /**\n * If set, will make the button take up all available space horizontally\n */\n fullWidth?: boolean\n /**\n * Similar to \"link\", but without an underline and possibly in different colors\n */\n text?: boolean\n /**\n * Will remove paddings and background. Use for links.\n */\n link?: boolean\n /**\n * color:\n * primary: the default primary blue.\n * outline: foundation background and outline\n * subtle: no styling\n */\n color?: FormButtonStyle\n /**\n * Should rounded-full be added?:\n */\n rounded?: boolean\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?: boolean\n /**\n * Whether to disable the button so that it can't be pressed\n */\n disabled?: boolean\n /**\n * If set, will have type set to \"submit\" to enable it to submit any parent forms\n */\n submit?: boolean\n /**\n * Add icon to the left from the text\n */\n iconLeft?: Nullable<PropAnyComponent>\n /**\n * Add icon to the right from the text\n */\n iconRight?: Nullable<PropAnyComponent>\n /**\n * Hide default slot (when you want to show icons only)\n */\n hideText?: boolean\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?: Nullable<PropAnyComponent>\n /**\n * Disables the button and shows a spinning loader\n */\n loading?: boolean\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(() =>\n props.loading ? CommonLoadingIcon : props.iconLeft\n)\n\nconst bgAndBorderClasses = computed(() => {\n const classParts: string[] = []\n\n const colorsBgBorder = {\n subtle: [\n 'bg-transparent border-transparent text-foreground font-medium',\n 'hover:bg-primary-muted disabled:hover:bg-transparent focus-visible:border-foundation'\n ],\n outline: [\n 'bg-foundation border-outline-2 text-foreground font-medium',\n 'hover:bg-primary-muted disabled:hover:bg-foundation focus-visible:border-foundation'\n ],\n danger: [\n 'bg-danger border-danger-darker text-foundation font-medium',\n 'hover:bg-danger-darker disabled:hover:bg-danger focus-visible:border-foundation'\n ],\n primary: [\n 'bg-primary border-outline-1 text-foreground-on-primary font-semibold',\n 'hover:bg-primary-focus disabled:hover:bg-primary focus-visible:border-foundation'\n ]\n }\n\n if (props.rounded) {\n classParts.push('!rounded-full')\n }\n\n if (props.text || props.link) {\n switch (props.color) {\n case 'subtle':\n classParts.push('text-foreground')\n break\n case 'outline':\n classParts.push('text-foreground')\n break\n case 'danger':\n classParts.push('text-danger')\n break\n case 'primary':\n default:\n classParts.push('text-primary')\n break\n }\n } else {\n switch (props.color) {\n case 'subtle':\n classParts.push(...colorsBgBorder.subtle)\n break\n case 'outline':\n classParts.push(...colorsBgBorder.outline)\n break\n case 'danger':\n classParts.push(...colorsBgBorder.danger)\n break\n case 'primary':\n default:\n classParts.push(...colorsBgBorder.primary)\n break\n }\n }\n\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed(() => {\n switch (props.size) {\n case 'sm':\n return 'h-6 text-body-2xs'\n case 'lg':\n return 'h-10 text-body-sm'\n default:\n case 'base':\n return 'h-8 text-body-xs'\n }\n})\n\nconst paddingClasses = computed(() => {\n if (props.text || props.link) {\n return 'p-0'\n }\n\n const hasIconLeft = !!props.iconLeft\n const hasIconRight = !!props.iconRight\n const hideText = props.hideText\n\n switch (props.size) {\n case 'sm':\n if (hideText) return 'w-6'\n if (hasIconLeft) return 'py-1 pr-2 pl-1'\n if (hasIconRight) return 'py-1 pl-2 pr-1'\n return 'px-2 py-1'\n case 'lg':\n if (hideText) return 'w-10'\n if (hasIconLeft) return 'py-2 pr-6 pl-4'\n if (hasIconRight) return 'py-2 pl-6 pr-4'\n return 'px-6 py-2'\n case 'base':\n default:\n if (hideText) return 'w-8'\n if (hasIconLeft) return 'py-0 pr-4 pl-2'\n if (hasIconRight) return 'py-0 pl-4 pr-2'\n return 'px-4 py-0'\n }\n})\n\nconst generalClasses = computed(() => {\n const baseClasses = [\n 'inline-flex justify-center items-center',\n 'text-center select-none whitespace-nowrap',\n 'outline outline-2 outline-transparent',\n 'transition duration-200 ease-in-out focus-visible:outline-outline-4'\n ]\n\n const additionalClasses = []\n\n if (!props.text && !props.link) {\n additionalClasses.push('rounded-md border')\n }\n\n if (props.fullWidth) {\n additionalClasses.push('w-full')\n } else if (!props.hideText) {\n additionalClasses.push('max-w-max')\n }\n if (isDisabled.value) {\n additionalClasses.push('cursor-not-allowed opacity-60')\n }\n\n return [...baseClasses, ...additionalClasses].join(' ')\n})\n\nconst buttonClasses = computed(() => {\n return [\n generalClasses.value,\n sizeClasses.value,\n bgAndBorderClasses.value,\n paddingClasses.value\n ].join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['shrink-0']\n\n switch (props.size) {\n case 'sm':\n classParts.push('h-4 w-4 p-0.5')\n break\n case 'lg':\n classParts.push('h-6 w-6 p-1')\n break\n case 'base':\n default:\n classParts.push('h-6 w-6 p-1')\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","<template>\n <FormButton\n :link=\"underline\"\n :text=\"!underline\"\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 = 'sm' | 'base' | 'lg'\nconst emit = defineEmits<{ (e: 'click', val: MouseEvent): void }>()\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 underline: {\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 Loading\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 id?: string\n}\n","<template>\n <div\n aria-live=\"assertive\"\n class=\"pointer-events-none fixed top-0 right-0 left-0 bottom-0 flex items-end px-4 py-6 mt-10 sm:items-start sm:p-6 z-[60]\"\n >\n <div class=\"flex w-full flex-col items-center space-y-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 bg-foundation text-foreground shadow-lg border border-outline-2 p-3\"\n :class=\"{ 'pb-2': isTitleOnly }\"\n >\n <div class=\"flex space-x-2\">\n <div class=\"flex-shrink-0 mt-1\">\n <CheckCircleIcon\n v-if=\"notification.type === ToastNotificationType.Success\"\n class=\"text-success h-4 w-4\"\n aria-hidden=\"true\"\n />\n <XCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Danger\"\n class=\"text-danger h-4 w-4\"\n aria-hidden=\"true\"\n />\n <ExclamationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Warning\"\n class=\"text-foreground-2 h-4 w-4\"\n aria-hidden=\"true\"\n />\n <InformationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Info\"\n class=\"text-foreground-2 h-4 w-4\"\n aria-hidden=\"true\"\n />\n <CommonLoadingIcon\n v-else-if=\"notification.type === ToastNotificationType.Loading\"\n class=\"h-4 w-4 opacity-80\"\n />\n </div>\n <div class=\"w-full min-w-[10rem]\">\n <p\n v-if=\"notification.title\"\n class=\"text-foreground-2 font-medium text-body-xs\"\n >\n {{ notification.title }}\n </p>\n <p\n v-if=\"notification.description\"\n class=\"text-foreground-2 text-body-xs leading-snug\"\n >\n {{ notification.description }}\n </p>\n <div v-if=\"notification.cta\">\n <TextLink\n class=\"mt-1 color-primary\"\n :to=\"notification.cta.url\"\n size=\"sm\"\n @click=\"onCtaClick\"\n >\n {{ notification.cta.title }}\n </TextLink>\n </div>\n </div>\n <div class=\"ml-2 flex-shrink-0 mt-0.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 TextLink from '~~/src/components/common/text/Link.vue'\nimport {\n CheckCircleIcon,\n XCircleIcon,\n ExclamationCircleIcon,\n InformationCircleIcon,\n XMarkIcon\n} from '@heroicons/vue/20/solid'\nimport { computed } from 'vue'\nimport type { MaybeNullOrUndefined } from '@speckle/shared'\nimport { ToastNotificationType } from '~~/src/helpers/global/toast'\nimport type { ToastNotification } from '~~/src/helpers/global/toast'\nimport { CommonLoadingIcon } from '~~/src/lib'\n\nconst emit = defineEmits<{\n (e: 'update:notification', val: MaybeNullOrUndefined<ToastNotification>): void\n}>()\n\nconst props = defineProps<{\n notification: MaybeNullOrUndefined<ToastNotification>\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 * @deprecated Use vKeyboardClickable directive instead\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 <span class=\"whitespace-nowrap\">\n <slot>Badge</slot>\n </span>\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'\ntype BadgeColors = 'primary' | 'secondary'\n\nconst emit = defineEmits<{\n (e: 'click-icon', v: MouseEvent): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n size?: BadgeSize\n color?: BadgeColors\n /**\n * Set text & bg color. Defaults to primary variation.\n */\n colorClasses?: string\n\n /**\n * Show dot to the right\n */\n dot?: boolean\n\n /**\n * Set dot/icon bg color. Defaults to primary variation.\n */\n dotIconColorClasses?: string\n\n /**\n * Optionally show icon to the left of the text\n */\n iconLeft?: PropAnyComponent\n\n /**\n * A more square, but still rounded look\n */\n rounded?: boolean\n\n /**\n * Track icon clicks\n */\n clickableIcon?: boolean\n }>(),\n {\n size: 'base',\n color: 'primary'\n }\n)\n\nconst badgeColorClasses = computed(() =>\n props.colorClasses || props.color === 'primary'\n ? 'bg-info-lighter text-primary-focus dark:text-foreground'\n : 'bg-highlight-3 text-foreground-2'\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 select-none',\n badgeColorClasses.value,\n props.size === 'lg'\n ? 'px-3 py-0.5 text-body-2xs'\n : 'p-1 text-body-3xs text-body-3xs font-medium'\n ]\n\n if (props.rounded) {\n classParts.push('rounded')\n classParts.push(\n props.size === 'lg'\n ? 'px-2 py-0.5 text-body-2xs'\n : 'px-1.1 py-0.5 text-body-3xs font-medium'\n )\n } else {\n classParts.push('rounded-full')\n classParts.push(\n props.size === 'lg'\n ? 'px-2.5 py-0.5 text-body-2xs'\n : 'px-2.5 py-0.5 text-body-3xs 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 = 768,\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-6'\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-6',\n 'md:space-x-6',\n 'lg:space-x-6',\n 'xl:space-x-6',\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 class=\"flex space-x-2 items-center\">\n <div\n class=\"shrink-0 h-7 w-7 rounded-full border border-primary text-white bg-primary inline-flex items-center justify-center select-none\"\n >\n <CheckIcon class=\"w-4 h-4\" />\n </div>\n <div class=\"flex flex-col\">\n <div class=\"text-body-xs font-medium text-primary\">{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"text-body-2xs text-foreground-2\">\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 class=\"flex space-x-2 items-center\">\n <div\n class=\"shrink-0 h-7 w-7 text-body-xs rounded-full border border-primary inline-flex items-center justify-center select-none text-primary\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div class=\"text-body-xs font-medium text-primary\">{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"text-body-2xs text-foreground-2\">\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 class=\"flex space-x-2 items-center\">\n <div\n class=\"shrink-0 h-7 w-7 rounded-full border border-foreground-3 inline-flex items-center justify-center select-none text-foreground-3\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div class=\"text-body-xs font-medium text-foreground-2\">\n {{ step.name }}\n </div>\n <div v-if=\"step.description\" class=\"text-body-2xs text-foreground-2\">\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<{\n (e: 'update:modelValue', val: number): void\n}>()\n\nconst props = defineProps<{\n ariaLabel?: string\n orientation?: HorizontalOrVertical\n steps: NumberStepType[]\n modelValue?: number\n goVerticalBelow?: TailwindBreakpoints\n nonInteractive?: boolean\n stepsPadding?: StepsPadding\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<{\n (e: 'update:modelValue', val: number): void\n}>()\n\nconst props = defineProps<{\n ariaLabel?: string\n basic?: boolean\n orientation?: HorizontalOrVertical\n steps: BulletStepType[]\n modelValue?: number\n goVerticalBelow?: TailwindBreakpoints\n nonInteractive?: boolean\n stepsPadding?: StepsPadding\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 top-0 left-0 right-0 bottom-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)\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 void 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<{\n (e: 'update:modelValue', v: boolean): void\n (e: 'click', v: MouseEvent): void\n}>()\n\nconst props = defineProps<{\n disabled?: boolean\n modelValue?: 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\n class=\"relative flex\"\n :class=\"labelPosition === 'left' ? 'flex-row-reverse items-center' : 'items-start'\"\n >\n <div\n class=\"flex h-6 items-center\"\n :class=\"labelPosition === 'left' ? 'w-1/2 justify-end mr-2' : ''\"\n >\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=\"checkboxClasses\"\n v-bind=\"$attrs\"\n @change=\"onChange\"\n />\n </div>\n <div class=\"text-sm\" :class=\"labelPosition === 'left' ? 'w-1/2' : 'ml-2'\">\n <label :for=\"finalId\" :class=\"{ 'sr-only': hideLabel }\">\n <span class=\"text-body-xs text-foreground font-medium\">{{ title }}</span>\n <span v-if=\"showRequired\" class=\"text-danger ml-1\">*</span>\n <p v-if=\"descriptionText\" :id=\"descriptionId\" :class=\"descriptionClasses\">\n {{ descriptionText }}\n </p>\n </label>\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'\nimport type { LabelPosition } from '~~/src/composables/form/input'\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 labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits<{\n (e: 'update:modelValue', val: ValueType): void\n}>()\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 descriptionText = computed(() => props.description || errorMessage.value)\nconst descriptionId = computed(() => `${props.name}-description`)\nconst descriptionClasses = computed((): string => {\n const classParts: string[] = ['text-body-2xs']\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 checkboxClasses = computed(() => {\n const classParts = [\n 'h-3.5 w-3.5 rounded',\n 'border bg-foundation text-primary',\n 'hover:border-foreground-2 focus:ring-1 focus:ring-outline-4 focus:ring-offset-1',\n 'disabled:cursor-not-allowed disabled:opacity-60'\n ]\n\n if (errorMessage.value) {\n classParts.push('border-danger-lighter')\n } else {\n classParts.push('border-outline-5')\n }\n\n return classParts.join(' ')\n})\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 space-x-2 mb-2 last:mb-0\"\n :class=\"description && inlineDescription ? 'items-start' : 'items-center'\"\n >\n <div class=\"flex items-center\" :class=\"size === 'sm' ? 'h-4' : 'h-6'\">\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=\"[\n inlineDescription ? 'flex space-x-2 items-center' : '',\n size === 'sm' ? 'text-body-2xs' : 'text-body-xs'\n ]\"\n >\n <label\n :for=\"finalId\"\n class=\"text-foreground flex space-x-2 items-center\"\n :class=\"{ 'sr-only': hideLabel }\"\n >\n <div v-if=\"icon\">\n <component\n :is=\"icon\"\n :class=\"[\n size === 'sm' ? 'h-6 sm:h-8 w-6 sm:w-8' : 'h-8 w-8 sm:h-10 sm:w-10'\n ]\"\n />\n </div>\n <div class=\"flex flex-col\">\n <span class=\"font-medium\">{{ 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[]\ntype Size = 'sm' | 'base'\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 size: {\n type: String as PropType<Optional<Size>>,\n default: 'base'\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits<{\n (e: 'update:modelValue', val: ValueType): void\n}>()\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-body-3xs']\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","<template>\n <div class=\"w-full\">\n <div\n class=\"flex items-stretch w-full\"\n :class=\"\n isStacked\n ? 'flex-col space-y-3 '\n : 'flex-col sm:flex-row space-y-3 sm:space-y-0 sm:space-x-3'\n \"\n >\n <div v-for=\"option in options\" :key=\"option.value\" class=\"w-full flex flex-col\">\n <button\n class=\"bg-foundation relative w-full h-full select-none rounded-md border shadow\"\n :class=\"[\n selected === option.value ? 'border-outline-4' : 'border-outline-2',\n disabled ? 'opacity-60 cursor-not-allowed' : 'hover:border-outline-1'\n ]\"\n :disabled=\"disabled\"\n @click=\"selectItem(option.value)\"\n >\n <div class=\"p-4 flex flex-col space-y-2 h-full\">\n <div\n class=\"flex justify-between gap-x-3\"\n :class=\"option.icon ? 'items-start' : 'items-center'\"\n >\n <div class=\"flex flex-1 items-start text-left gap-x-2\">\n <component\n :is=\"option.icon\"\n v-if=\"option.icon\"\n class=\"text-foreground h-8 w-8 -mt-1 stroke-[1px]\"\n />\n <div class=\"flex flex-col\">\n <h4 :class=\"titleClasses\">\n {{ option.title }}\n </h4>\n <h5 v-if=\"option.subtitle\" class=\"text-foreground-3 text-body-xs\">\n {{ option.subtitle }}\n </h5>\n </div>\n </div>\n <div\n class=\"h-5 w-5 rounded-full flex items-center justify-center border-[1.5px] border-outline-5\"\n >\n <div\n v-if=\"selected === option.value\"\n class=\"h-2.5 w-2.5 rounded-full bg-primary flex\"\n ></div>\n </div>\n </div>\n <div\n v-if=\"option.introduction\"\n class=\"text-body-2xs text-foreground pb-1 select-none text-left pr-20\"\n >\n {{ option.introduction }}\n </div>\n <slot :name=\"option.value\" />\n </div>\n </button>\n <div\n v-if=\"option.help\"\n class=\"sm:hidden text-xs flex space-x-0.5 mt-2 text-foreground\"\n >\n <InformationCircleIcon class=\"h-4 w-4\" />\n {{ option.help }}\n </div>\n </div>\n </div>\n <div v-if=\"!isStacked\" class=\"hidden sm:flex space-x-3 w-full\">\n <div v-for=\"option in options\" :key=\"option.value\" class=\"w-full\">\n <div\n v-if=\"option.help\"\n class=\"text-xs flex space-x-0.5 mt-2 text-foreground select-none\"\n >\n <InformationCircleIcon class=\"h-4 w-4\" />\n {{ option.help }}\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Value extends string\">\nimport { InformationCircleIcon } from '@heroicons/vue/24/outline'\nimport { type ConcreteComponent, computed } from 'vue'\n\ntype OptionType = {\n value: Value\n title: string\n subtitle?: string\n introduction?: string\n icon?: ConcreteComponent\n help?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n options: OptionType[]\n disabled?: boolean\n isStacked?: boolean\n size?: 'sm' | 'base'\n }>(),\n {\n size: 'base'\n }\n)\n\nconst selected = defineModel<Value>()\n\nconst selectItem = (value: Value) => {\n selected.value = value\n}\n\nconst titleClasses = computed(() => {\n const classes = ['font-medium text-foreground']\n if (props.size === 'sm') {\n classes.push('text-body-sm')\n } else {\n classes.push('text-body')\n }\n return classes\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, watch } from 'vue'\nimport type { Ref, ToRefs } from 'vue'\nimport type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\nimport { debounce, isArray, isBoolean, isString, isUndefined, noop } from 'lodash'\nimport type { LabelPosition } from './input'\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 customErrorMessage?: string\n hideErrorMessage?: boolean\n color?: InputColor\n labelPosition?: LabelPosition\n customHelpClass?: string\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: veeErrorMessage } = useField<V>(\n props.name,\n props.rules,\n {\n validateOnMount: unref(props.validateOnMount),\n validateOnValueUpdate: unref(props.validateOnValueUpdate),\n initialValue: unref(props.modelValue) || undefined\n }\n )\n\n const labelClasses = computed(() => {\n const classParts = [\n 'flex text-body-xs font-medium gap-1 items-center',\n unref(props.color) === 'foundation' ? 'text-foreground' : 'text-foreground-2',\n unref(props.labelPosition) !== 'left' ? 'pb-1' : null\n ]\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-md'\n ]\n\n return classParts.join(' ')\n })\n\n const coreClasses = computed(() => {\n const classParts = [\n 'block w-full text-foreground transition-all text-body-sm',\n coreInputClasses.value\n ]\n\n if (hasError.value) {\n classParts.push('!border-danger')\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(\n 'bg-foundation !border border-outline-2 hover:border-outline-5 focus-visible:border-outline-4 !ring-0 focus-visible:!outline-0'\n )\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\n const errorMessage = computed(() => {\n if (unref(props.customErrorMessage)) {\n return unref(props.customErrorMessage)\n }\n\n const base = veeErrorMessage.value\n if (!base || !unref(props.useLabelInErrors)) return base\n return base.replace('Value', title.value)\n })\n\n const hasError = computed(() => !!errorMessage.value)\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 customHelpTipClass = computed(() => unref(props.customHelpClass))\n const helpTipId = computed(() =>\n hasHelpTip.value ? `${unref(props.name)}-${internalHelpTipId.value}` : undefined\n )\n const helpTipClasses = computed((): string => {\n const classParts = ['text-body-2xs break-words']\n classParts.push(hasError.value ? 'text-danger' : 'text-foreground-2')\n if (customHelpTipClass.value) {\n classParts.push(customHelpTipClass.value)\n }\n return classParts.join(' ')\n })\n const shouldShowClear = computed(() => {\n if (!unref(props.showClear)) return false\n return (value.value?.length || 0) > 0\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 shouldShowClear,\n hasError\n }\n}\n\ntype FormInputChangeEvent = { event?: Event; value: string }\n\n/**\n * Attach returned on and bind using v-on and v-bind, and then you can use the returned `value`\n * ref to get the input's value while ensuring normal input events are debounced and only change/clear\n * events cause the value to propagate immediately\n *\n * Very useful for search inputs and other kind of auto-submitting inputs!\n */\nexport function useDebouncedTextInput(params?: {\n /**\n * For how long should basic input events be debounced.\n * Default: 1000 (ms)\n */\n debouncedBy?: number\n\n /**\n * Optionally pass in the model ref that should be used as the source of truth\n */\n model?: Ref<MaybeNullOrUndefined<string>>\n\n /**\n * Set to true if you're tracking changes on a basic HTML input element. This will change the events\n * being used (e.g. input instead of update:modelValue)\n *\n * Default: false\n */\n isBasicHtmlInput?: boolean\n\n /**\n * Set to false if you don't want the change event to be emitted on Enter key press.\n * Setting only works for basic html inputs currently!\n *\n * Default: Default behavior (true for input, false for textarea)\n */\n submitOnEnter?: boolean\n\n /**\n * Set to true if you want to see debug output for how events fire and are handled\n */\n debug?: boolean | ((...logArgs: unknown[]) => void)\n}) {\n const { debouncedBy = 1000, isBasicHtmlInput = false, submitOnEnter } = params || {}\n const log = params?.debug\n ? isBoolean(params.debug)\n ? console.debug\n : params.debug\n : noop\n\n const value = params?.model || ref('')\n const model = ref(value.value)\n\n const getValue = (val: string | InputEvent | Event | FormInputChangeEvent) => {\n if (isString(val)) return val\n if ('value' in val) return val.value\n\n const target = val.target as Nullable<HTMLInputElement | HTMLTextAreaElement>\n return target?.value || ''\n }\n\n const debouncedValueUpdate = debounce((val: string) => {\n value.value = val\n log('Value updated: ' + val)\n }, debouncedBy)\n\n const inputEventName = isBasicHtmlInput ? 'input' : 'update:modelValue'\n const on = {\n [inputEventName]: (val: string | InputEvent) => {\n const newVal = getValue(val)\n model.value = newVal\n debouncedValueUpdate(newVal)\n log(`Input event [${inputEventName}] triggered: ${newVal}`)\n },\n clear: () => {\n debouncedValueUpdate.cancel()\n model.value = ''\n value.value = ''\n log('Clear event')\n },\n change: (val: FormInputChangeEvent | Event) => {\n const newVal = getValue(val)\n debouncedValueUpdate.cancel()\n value.value = newVal\n model.value = newVal\n log('Change event: ' + newVal)\n },\n keydown: (e: KeyboardEvent) => {\n if (!isBasicHtmlInput) return\n if (isUndefined(submitOnEnter)) return\n\n const isEnter = e.key === 'Enter'\n if (!isEnter) return\n\n const isTextarea = e.target instanceof HTMLTextAreaElement\n\n if (isTextarea) {\n if (submitOnEnter) {\n log('Triggering submit on enter')\n e.preventDefault()\n e.stopPropagation()\n on.change(e)\n }\n } else {\n if (!submitOnEnter) {\n log('Preventing submit on enter')\n e.preventDefault()\n e.stopPropagation()\n }\n }\n }\n }\n const bind = computed(() => ({\n modelValue: model.value || ''\n }))\n\n watch(value, (newVal, oldVal) => {\n if (oldVal === newVal && !oldVal && !newVal) return\n if (model.value === value.value) return\n model.value = value.value\n })\n\n return {\n on,\n bind,\n value\n }\n}\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div :class=\"computedWrapperClasses\">\n <div\n :class=\"\n labelPosition === 'left'\n ? 'w-full md:w-6/12 flex flex-col justify-center'\n : 'w-full'\n \"\n >\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n <div v-if=\"!showRequired\" class=\"text-body-2xs font-normal\">(optional)</div>\n </label>\n <span\n v-if=\"labelPosition === 'left' && helpTipId\"\n :id=\"`${helpTipId}-left`\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </span>\n </div>\n <div\n class=\"relative\"\n :class=\"labelPosition === 'left' ? 'w-full md:w-6/12' : 'w-full'\"\n >\n <textarea\n :id=\"name\"\n ref=\"inputElement\"\n v-model=\"value\"\n :name=\"name\"\n :class=\"[\n coreClasses,\n iconClasses,\n sizeClasses,\n textareaClasses || '',\n 'min-h-[6rem] sm:min-h-[3rem] simple-scrollbar'\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 @keydown.stop\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 <p\n v-if=\"labelPosition === 'top' && helpTipId\"\n :id=\"`${helpTipId}-top`\"\n :class=\"['mt-1.5', helpTipClasses]\"\n >\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { 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 { LabelPosition } from '~~/src/composables/form/input'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\n\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', val: string): void\n (e: 'change', val: { event?: Event; value: string }): void\n (e: 'input', val: { event?: Event; value: string }): void\n (e: 'clear'): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n /**\n * Unique ID for the input (must be unique page-wide)\n */\n name: string\n showLabel?: boolean\n help?: string\n placeholder?: string\n label?: string\n disabled?: boolean\n rules?: RuleExpression<string>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n useLabelInErrors?: boolean\n autoFocus?: boolean\n modelValue?: string\n showClear?: boolean\n fullWidth?: boolean\n showRequired?: boolean\n showOptional?: boolean\n color?: InputColor\n textareaClasses?: string\n size?: InputSize\n labelPosition?: LabelPosition\n wrapperClasses?: string\n }>(),\n {\n useLabelInErrors: true,\n modelValue: '',\n color: 'page',\n labelPosition: 'top',\n wrapperClasses: ''\n }\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 shouldShowClear\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 (shouldShowClear.value && errorMessage.value) {\n classParts.push('pr-12')\n } else if (shouldShowClear.value || errorMessage.value) {\n classParts.push('pr-8')\n }\n\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed((): string => {\n switch (props.size) {\n case 'sm':\n return 'text-2xs !leading-tight'\n case 'lg':\n return 'text-sm'\n case 'xl':\n return 'text-base'\n case 'base':\n default:\n return 'text-body-xs'\n }\n})\n\nconst computedWrapperClasses = computed(() => {\n const classes = ['flex', props.wrapperClasses]\n if (props.fullWidth) {\n classes.push('w-full')\n }\n\n if (props.labelPosition === 'top') {\n classes.push('flex-col')\n }\n if (props.labelPosition === 'left') {\n classes.push(\n 'w-full space-y-1 sm:space-y-0 sm:space-x-8 flex-col sm:flex-row items-start'\n )\n }\n return classes.join(' ')\n})\n\ndefineExpose({ focus })\n</script>\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div :class=\"computedWrapperClasses\">\n <div\n :class=\"\n labelPosition === 'left'\n ? 'w-full md:w-6/12 flex flex-col justify-center'\n : 'w-full'\n \"\n >\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n <div v-if=\"showRequired\" class=\"text-danger text-body-xs opacity-80\">*</div>\n <div v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">(optional)</div>\n </label>\n <p\n v-if=\"labelPosition === 'left' && helpTipId && !hideHelpTip\"\n :id=\"helpTipId\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n\n <div\n class=\"group relative\"\n :class=\"labelPosition === 'left' ? 'w-full md:w-6/12' : 'w-full'\"\n >\n <div\n v-if=\"customIcon\"\n class=\"pointer-events-none absolute top-0 bottom-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 </div>\n <div\n v-if=\"loading\"\n class=\"absolute top-0 h-full right-0 flex items-center pr-2 text-foreground-3\"\n >\n <CommonLoadingIcon />\n </div>\n\n <div v-tippy=\"tooltipText\">\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 :readonly=\"readOnly\"\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 @keydown.stop\n />\n </div>\n <slot name=\"input-right\">\n <a\n v-if=\"rightIcon\"\n :title=\"rightIconTitle\"\n :class=\"[\n sizeClasses,\n readOnly\n ? 'w-full cursor-text border border-transparent group-hover:border-outline-5 rounded-md'\n : 'cursor-pointer'\n ]\"\n class=\"absolute top-0 right-0 hidden group-hover:flex items-center justify-end pr-1 text-foreground-2\"\n @click=\"onRightIconClick\"\n @keydown=\"onRightIconClick\"\n >\n <span class=\"text-body-xs sr-only\">{{ rightIconTitle }}</span>\n <Component\n :is=\"rightIcon\"\n class=\"h-6 w-6 text-foreground\"\n aria-hidden=\"true\"\n />\n </a>\n <a\n v-else-if=\"shouldShowClear\"\n title=\"Clear input\"\n class=\"absolute top-0 bottom-0 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-body-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-else-if=\"!showLabel && showRequired && !errorMessage\"\n class=\"pointer-events-none absolute top-0 bottom-0 mt-2 text-body right-0 flex items-center text-danger pr-2.5\"\n :class=\"[shouldShowClear ? 'pr-8' : 'pr-2']\"\n >\n *\n </div>\n </slot>\n </div>\n <p\n v-if=\"labelPosition === 'top' && helpTipId && !hideHelpTip\"\n :id=\"helpTipId\"\n :class=\"['mt-1.5', helpTipClasses]\"\n >\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { RuleExpression } from 'vee-validate'\nimport { XMarkIcon } 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'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport type { LabelPosition } from '~~/src/composables/form/input'\nimport { CommonLoadingIcon } from '~~/src/lib'\nimport { directive as vTippy } from 'vue-tippy'\n\ntype InputType = 'text' | 'email' | 'password' | 'url' | 'search' | 'number' | string\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\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 show the \"optional\" text\n */\n showOptional: {\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 * Whether to disable editing the component, making it read only\n */\n readOnly: {\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 inputClasses: {\n type: String,\n default: null\n },\n fullWidth: {\n type: Boolean,\n default: false\n },\n loading: {\n type: Boolean,\n default: false\n },\n hideErrorMessage: {\n type: Boolean,\n default: false\n },\n customErrorMessage: {\n type: String,\n default: null\n },\n wrapperClasses: {\n type: String,\n default: () => ''\n },\n color: {\n type: String as PropType<InputColor>,\n default: 'page'\n },\n labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n },\n rightIcon: {\n type: [Object, Function] as PropType<Optional<PropAnyComponent>>,\n default: undefined\n },\n rightIconTitle: {\n type: String,\n default: undefined\n },\n tooltipText: {\n type: String,\n default: undefined\n },\n customHelpClass: {\n type: String,\n default: undefined\n }\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', val: string): void\n (e: 'change', val: { event?: Event; value: string }): void\n (e: 'input', val: { event?: Event; value: string }): void\n (e: 'clear'): void\n (e: 'focus'): void\n (e: 'blur'): void\n (e: 'rightIconClick'): void\n}>()\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 shouldShowClear\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl: inputElement\n})\n\nconst leadingIconClasses = computed(() => {\n const classParts: string[] = ['h-4 w-4']\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 iconClasses = computed((): string => {\n const classParts: string[] = []\n\n if (props.customIcon) {\n classParts.push('pl-8')\n }\n\n if (!slots['input-right']) {\n if (props.rightIcon || errorMessage.value || shouldShowClear.value) {\n classParts.push('pr-8')\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-body-sm'\n case 'lg':\n return 'h-10 text-[13px]'\n case 'xl':\n return 'h-14 text-sm'\n case 'base':\n default:\n return 'h-8 text-body-sm'\n }\n})\n\nconst computedWrapperClasses = computed(() => {\n const classes = ['flex', props.wrapperClasses]\n if (props.fullWidth) {\n classes.push('w-full')\n }\n\n if (props.labelPosition === 'top') {\n classes.push('flex-col')\n }\n if (props.labelPosition === 'left') {\n classes.push('w-full space-y-1 sm:space-y-0 sm:space-x-8 flex-col sm:flex-row')\n }\n return classes.join(' ')\n})\n\nconst onRightIconClick = () => {\n emit('rightIconClick')\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 = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\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\n/**\n * Used for placeholders inputs where the user can leave the field empty\n */\nexport const isEmailOrEmpty: GenericValidateFunction<string> = (val) =>\n (val || '').match(VALID_EMAIL) || !val\n ? true\n : '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 can't be longer than ${maxLength} characters`\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\nexport const isMultiItemSelected = <T>(val: T[] | unknown): true | string => {\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 :class=\"[\n 'relative w-full h-1 bg-blue-500/30 text-xs text-foreground-on-primary overflow-hidden rounded-xl',\n showBar ? 'opacity-100' : 'opacity-0'\n ]\"\n >\n <div class=\"swoosher relative top-0 bg-blue-500/50\"></div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { useMounted } from '@vueuse/core'\nimport { computed } from 'vue'\n\nconst props = defineProps<{ loading: boolean; clientOnly?: boolean }>()\n\nconst mounted = useMounted()\nconst showBar = computed(() => (mounted.value || !props.clientOnly) && props.loading)\n</script>\n<style scoped>\n.swoosher {\n width: 100%;\n height: 100%;\n animation: swoosh 1s infinite linear;\n transform-origin: 0% 30%;\n}\n\n@keyframes swoosh {\n 0% {\n transform: translateX(0) scaleX(0);\n }\n\n 40% {\n transform: translateX(0) scaleX(0.4);\n }\n\n 100% {\n transform: translateX(100%) scaleX(0.5);\n }\n}\n</style>\n","<template>\n <!-- If multiple, use FormSelectMultiple instead -->\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 :class=\"{\n 'md:flex md:items-center md:space-x-2 md:justify-between': isLeftLabelPosition\n }\"\n >\n <div class=\"flex flex-col\" :class=\"{ 'pb-1': showLabel && !isLeftLabelPosition }\">\n <ListboxLabel\n :id=\"labelId\"\n class=\"flex text-body-xs text-foreground font-medium\"\n :class=\"[{ 'sr-only': !showLabel }, { 'items-center gap-1': showOptional }]\"\n :for=\"buttonId\"\n >\n {{ label }}\n <div v-if=\"showRequired\" class=\"text-danger text-xs opacity-80\">*</div>\n <div v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">\n (optional)\n </div>\n </ListboxLabel>\n <p\n v-if=\"helpTipId && isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"text-xs\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n <div v-tippy=\"tooltipText\">\n <div :class=\"buttonsWrapperClasses\">\n <!-- <div class=\"relative flex\"> -->\n <ListboxButton\n :id=\"buttonId\"\n ref=\"listboxButton\"\n v-slot=\"{ open }\"\n :class=\"buttonClasses\"\n >\n <div class=\"flex items-center justify-between w-full\">\n <div\n class=\"block truncate grow text-left text-xs sm:text-[13px]\"\n :class=\"[hasValueSelected ? 'text-foreground' : 'text-foreground-2']\"\n >\n <template\n v-if=\"\n !wrappedValue || (isArray(wrappedValue) && !wrappedValue.length)\n \"\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\n class=\"pointer-events-none shrink-0 ml-1 flex items-center space-x-2\"\n >\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=\"!showLabel && 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 <!-- Sync isOpen with dropdown open state -->\n <template v-if=\"(isOpen = open)\"></template>\n </ListboxButton>\n <!-- </div> -->\n <!-- Clear Button -->\n <button\n v-if=\"renderClearButton\"\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 top-0 bottom-0 left-0 flex items-center pl-2\"\n >\n <MagnifyingGlassIcon class=\"h-4 w-4 text-foreground-2\" />\n </div>\n <input\n ref=\"searchInput\"\n v-model=\"searchValue\"\n type=\"text\"\n class=\"py-1 pl-7 w-full bg-foundation placeholder:font-normal normal placeholder:text-foreground-2 text-[13px] focus-visible:[box-shadow:none] rounded-md hover:border-outline-5 focus-visible:border-outline-4\"\n :placeholder=\"searchPlaceholder\"\n @keydown.stop\n />\n </div>\n </label>\n <div class=\"overflow-auto simple-scrollbar max-h-60\">\n <div v-if=\"isAsyncSearchMode && isAsyncLoading\" class=\"px-1\">\n <CommonLoadingBar :loading=\"true\" />\n </div>\n <div v-else-if=\"isAsyncSearchMode && !currentItems.length\">\n <div class=\"text-foreground-2 text-center\">\n <slot name=\"nothing-found\">Nothing found</slot>\n </div>\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 as SingleItem)\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n <li\n v-tippy=\"\n disabledItemPredicate?.(item)\n ? disabledItemTooltip\n : undefined\n \"\n :class=\"\n listboxOptionClasses({\n active,\n disabled: disabledItemPredicate?.(item) || false\n })\n \"\n >\n <span\n class=\"block px-2 py-1.5 rounded-md\"\n :class=\"[\n selected ? 'bg-highlight-3' : '',\n !hideCheckmarks ? 'pr-8' : 'pr-2',\n !disabledItemPredicate?.(item) && !selected\n ? 'hover:bg-highlight-1'\n : ''\n ]\"\n >\n <slot\n name=\"option\"\n class=\"truncate\"\n :item=\"item\"\n :active=\"active\"\n :selected=\"selected\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n {{ simpleDisplayText(item) }}\n </slot>\n\n <span\n v-if=\"!hideCheckmarks && selected\"\n :class=\"[\n 'absolute top-0 bottom-0 right-0 text-foreground flex items-center pr-4'\n ]\"\n >\n <CheckIcon class=\"h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </span>\n </li>\n </ListboxOption>\n </template>\n </div>\n </ListboxOptions>\n </Teleport>\n </Transition>\n </div>\n </div>\n </Listbox>\n <p\n v-if=\"helpTipId && !isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"mt-2 text-xs\"\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>\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/20/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 { useElementBounding, useMounted, useIntersectionObserver } from '@vueuse/core'\nimport type { LabelPosition } from '~~/src/composables/form/input'\nimport { directive as vTippy } from 'vue-tippy'\n\ntype ButtonStyle = 'base' | 'simple' | 'tinted'\ntype ValueType = SingleItem | SingleItem[] | undefined\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\n\nconst isObjectLikeType = (v: unknown): v is Record<string, unknown> => isObjectLike(v)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: ValueType): void\n}>()\n\nconst props = defineProps({\n size: {\n type: String as PropType<Optional<InputSize>>,\n default: undefined\n },\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<\n Optional<RuleExpression<ValueType>>\n >,\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 /**\n * @deprecated Use size attribute instead\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 show the optional text\n */\n showOptional: {\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 labelId: {\n type: String,\n default: undefined\n },\n buttonId: {\n type: String,\n default: undefined\n },\n /**\n * Tooltip shown on disabled items\n */\n disabledItemTooltip: {\n required: false,\n type: String\n },\n labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n },\n tooltipText: {\n type: String,\n default: undefined\n }\n})\n\nconst { value, errorMessage: error } = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\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())\nconst isOpen = ref(false)\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 isLeftLabelPosition = computed(() => props.labelPosition === 'left')\n\nconst renderClearButton = computed(\n () => props.buttonStyle !== 'simple' && props.clearable && !props.disabled\n)\n\nconst sizeClasses = computed((): string => {\n if (!props.size) return ''\n\n switch (props.size) {\n case 'sm':\n return 'h-6 text-body-sm'\n case 'lg':\n return 'h-10 text-[13px]'\n case 'xl':\n return 'h-14 text-sm'\n case 'base':\n default:\n return 'h-8 text-body-sm'\n }\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')\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('border border-danger')\n }\n } else if (props.buttonStyle !== 'simple') {\n classParts.push('rounded-md border')\n if (isOpen.value) {\n classParts.push('border-outline-4')\n } else {\n classParts.push('border-outline-2 hover:border-outline-5 focus:outline-0')\n }\n }\n\n if (props.fixedHeight) {\n classParts.push('h-8')\n } else if (sizeClasses.value?.length) {\n classParts.push(sizeClasses.value)\n }\n\n if (isLeftLabelPosition.value) {\n classParts.push('md:basis-1/2')\n }\n\n return classParts.join(' ')\n})\n\nconst commonButtonClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.buttonStyle !== 'simple') {\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 focus:outline-outline-4 focus:outline-1',\n commonButtonClasses.value\n ]\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('p-2')\n\n if (!isDisabled.value) {\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-foundation 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 py-1 label label--light border border-outline-3 shadow-md 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-40')\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 { disabled } = params || {}\n\n const classParts = ['relative transition select-none py-1 px-2']\n\n if (disabled) {\n classParts.push('opacity-50 cursor-not-allowed')\n } else {\n classParts.push('text-foreground cursor-pointer')\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 void debouncedSearch()\n})\n\nonMounted(() => {\n if (isAsyncSearchMode.value && !props.items.length) {\n void 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 :label-id=\"labelId\"\n :button-id=\"buttonId\"\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<{\n (e: 'update:modelValue', v: ValueType): void\n}>()\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 labelId: {\n type: String\n },\n buttonId: {\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 :label-id=\"labelId\"\n :button-id=\"buttonId\"\n >\n <template #something-selected=\"{ value }\">\n <ul class=\"flex flex-wrap gap-1.5\">\n <li v-for=\"item in isArrayValue(value) ? value : [value]\" :key=\"item[by]\">\n <CommonBadge\n size=\"lg\"\n color-classes=\"border border-outline-2 bg-foundation-page\"\n dot-icon-color-classes=\"text-foreground\"\n rounded\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-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<{\n (e: 'update:modelValue', val: Array<SingleItem>): void\n}>()\n\nconst props = defineProps<{\n items: Array<SingleItem>\n label: string\n name: string\n help?: string\n modelValue?: SingleItem | SingleItem[] | undefined\n multiple?: boolean\n rules?: Array<any>\n by: string\n labelId?: string\n buttonId?: string\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>\n <div\n :key=\"forceUpdateKey\"\n :class=\"{\n 'md:flex md:items-center md:space-x-2 md:justify-between': isLeftLabelPosition\n }\"\n >\n <div class=\"flex flex-col\" :class=\"{ 'pb-1': showLabel && !isLeftLabelPosition }\">\n <label\n :id=\"labelId\"\n class=\"flex text-body-xs text-foreground font-medium pointer-events-none\"\n :class=\"[{ 'sr-only': !showLabel }, { 'items-center gap-1': showOptional }]\"\n :for=\"buttonId\"\n >\n {{ label }}\n <div v-if=\"showRequired\" class=\"text-danger text-xs opacity-80\">*</div>\n <div v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">\n (optional)\n </div>\n </label>\n <p\n v-if=\"helpTipId && isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"text-xs\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n <div v-tippy=\"tooltipText\">\n <div :class=\"buttonsWrapperClasses\">\n <button\n :id=\"buttonId\"\n ref=\"listboxButton\"\n type=\"button\"\n :class=\"buttonClasses\"\n :aria-expanded=\"isOpen\"\n :aria-haspopup=\"true\"\n @click=\"toggleDropdown\"\n >\n <div class=\"flex items-center justify-between w-full\">\n <div\n class=\"block truncate grow text-left text-xs sm:text-[13px]\"\n :class=\"[hasValueSelected ? 'text-foreground' : 'text-foreground-2']\"\n >\n <template\n v-if=\"\n !wrappedValue || (isArray(wrappedValue) && !wrappedValue.length)\n \"\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\n class=\"pointer-events-none shrink-0 ml-1 flex items-center space-x-2\"\n >\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=\"!showLabel && showRequired\"\n class=\"text-4xl text-danger opacity-50 h-4 w-4 leading-6\"\n >\n *\n </div>\n <ChevronUpIcon\n v-if=\"isOpen\"\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 </button>\n\n <button\n v-if=\"renderClearButton\"\n :class=\"clearButtonClasses\"\n :disabled=\"disabled\"\n @click=\"clearValue()\"\n >\n <XMarkIcon class=\"w-3 h-3\" />\n </button>\n\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 <div\n v-if=\"isOpen\"\n ref=\"menuEl\"\n :class=\"listboxOptionsClasses\"\n :style=\"listboxOptionsStyle\"\n role=\"listbox\"\n :aria-labelledby=\"labelId\"\n @focus=\"searchInput?.focus()\"\n >\n <!-- Search input section -->\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 top-0 bottom-0 left-0 flex items-center pl-2\"\n >\n <MagnifyingGlassIcon class=\"h-4 w-4 text-foreground-2\" />\n </div>\n <input\n ref=\"searchInput\"\n v-model=\"searchValue\"\n type=\"text\"\n class=\"py-1 pl-7 w-full bg-foundation placeholder:font-normal normal placeholder:text-foreground-2 text-[13px] focus-visible:[box-shadow:none] rounded-md hover:border-outline-5 focus-visible:border-outline-4\"\n :placeholder=\"searchPlaceholder\"\n @keydown.stop\n />\n </div>\n </label>\n\n <div\n ref=\"optionsContainer\"\n class=\"overflow-auto simple-scrollbar max-h-60 xl:max-h-80 gap-1 flex flex-col\"\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 <div class=\"text-foreground-2 text-center\">\n <slot name=\"nothing-found\">Nothing found</slot>\n </div>\n </div>\n <template v-if=\"!isAsyncSearchMode || !isAsyncLoading\">\n <button\n v-for=\"item in finalItems\"\n :key=\"itemKey(item)\"\n v-tippy=\"\n disabledItemPredicate?.(item) ? disabledItemTooltip : undefined\n \"\n type=\"button\"\n role=\"option\"\n :aria-selected=\"isSelected(item)\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n :class=\"\n listboxOptionClasses({\n disabled: disabledItemPredicate?.(item) || false\n })\n \"\n @click=\"(e) => selectItem(item, e)\"\n >\n <div\n class=\"block w-full px-2 py-1.5 rounded-md text-left flex items-center gap-1\"\n :class=\"[\n !hideCheckmarks ? 'pr-8' : 'pr-2',\n !disabledItemPredicate?.(item) && !isSelected(item)\n ? 'hover:bg-highlight-1'\n : ''\n ]\"\n >\n <FormCheckbox\n :name=\"`select-${itemKey(item)}`\"\n :checked=\"isSelected(item)\"\n :disabled=\"disabledItemPredicate?.(item)\"\n :hide-label=\"true\"\n @change.stop\n />\n <slot\n name=\"option\"\n class=\"truncate\"\n :item=\"item\"\n :selected=\"isSelected(item)\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n {{ simpleDisplayText(item) }}\n </slot>\n </div>\n </button>\n </template>\n </div>\n </div>\n </Teleport>\n </Transition>\n </div>\n </div>\n </div>\n <p\n v-if=\"helpTipId && !isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"mt-2 text-xs\"\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>\nimport {\n ChevronDownIcon,\n ChevronUpIcon,\n MagnifyingGlassIcon,\n XMarkIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/20/solid'\nimport { debounce, isArray, isObjectLike } from 'lodash'\nimport type { CSSProperties, PropType, Ref } from 'vue'\nimport { computed, onMounted, ref, unref, watch, nextTick } 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 {\n useElementBounding,\n useMounted,\n useIntersectionObserver,\n onClickOutside\n} from '@vueuse/core'\nimport type { LabelPosition } from '~~/src/composables/form/input'\nimport { directive as vTippy } from 'vue-tippy'\nimport FormCheckbox from '~~/src/components/form/Checkbox.vue'\n\ntype ButtonStyle = 'base' | 'simple' | 'tinted'\ntype ValueType = SingleItem | SingleItem[] | undefined\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\n\nconst isObjectLikeType = (v: unknown): v is Record<string, unknown> => isObjectLike(v)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: ValueType): void\n}>()\n\nconst props = defineProps({\n size: {\n type: String as PropType<Optional<InputSize>>,\n default: undefined\n },\n items: {\n type: Array as PropType<SingleItem[]>,\n default: () => []\n },\n modelValue: {\n type: [Array, Object, String, Number] 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<\n Optional<RuleExpression<ValueType>>\n >,\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 /**\n * @deprecated Use size attribute instead\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 show the optional text\n */\n showOptional: {\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 labelId: {\n type: String,\n default: undefined\n },\n buttonId: {\n type: String,\n default: undefined\n },\n /**\n * Tooltip shown on disabled items\n */\n disabledItemTooltip: {\n required: false,\n type: String\n },\n labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n },\n tooltipText: {\n type: String,\n default: undefined\n }\n})\n\nconst { value, errorMessage: error } = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n initialValue: isArray(props.modelValue) ? props.modelValue : []\n})\n\nconst isMounted = useMounted()\n\nconst searchInput = ref(null as Nullable<HTMLInputElement>)\nconst menuEl = ref<HTMLDivElement | null>(null)\nconst listboxButton = ref<HTMLButtonElement | null>(null)\nconst searchValue = ref('')\nconst currentItems = ref([]) as Ref<SingleItem[]>\nconst isAsyncLoading = ref(false)\nconst forceUpdateKey = ref(1)\nconst internalHelpTipId = ref(nanoid())\nconst isOpen = ref(false)\n\nconst listboxButtonBounding = useElementBounding(listboxButton, {\n windowResize: true,\n windowScroll: true,\n immediate: true\n})\n\nuseIntersectionObserver(\n computed(() => menuEl.value),\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 isLeftLabelPosition = computed(() => props.labelPosition === 'left')\n\nconst renderClearButton = computed(\n () => props.buttonStyle !== 'simple' && props.clearable && !props.disabled\n)\n\nconst sizeClasses = computed((): string => {\n if (!props.size) return ''\n\n switch (props.size) {\n case 'sm':\n return 'h-6 text-body-sm'\n case 'lg':\n return 'h-10 text-[13px]'\n case 'xl':\n return 'h-14 text-sm'\n case 'base':\n default:\n return 'h-8 text-body-sm'\n }\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')\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('border border-danger')\n }\n } else if (props.buttonStyle !== 'simple') {\n classParts.push('rounded-md border')\n if (isOpen.value) {\n classParts.push('border-outline-4')\n } else {\n classParts.push('border-outline-2 hover:border-outline-5 focus:outline-0')\n }\n }\n\n if (props.fixedHeight) {\n classParts.push('h-8')\n } else if (sizeClasses.value?.length) {\n classParts.push(sizeClasses.value)\n }\n\n if (isLeftLabelPosition.value) {\n classParts.push('md:basis-1/2')\n }\n\n return classParts.join(' ')\n})\n\nconst commonButtonClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.buttonStyle !== 'simple') {\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 focus:outline-outline-4 focus:outline-1',\n commonButtonClasses.value\n ]\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('p-2')\n\n if (!isDisabled.value) {\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-foundation 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 return isArray(currentValue) ? currentValue : []\n },\n set: (newVal) => {\n if (!isArray(newVal)) {\n console.warn('Attempting to set non-array value in selector')\n return\n }\n\n if (props.fullyControlValue) {\n emit('update:modelValue', newVal)\n } else {\n value.value = newVal\n }\n\n forceUpdateKey.value += 1\n }\n})\n\nconst hasValueSelected = computed(() => {\n if (isArray(wrappedValue.value)) return wrappedValue.value.length !== 0\n else return !!wrappedValue.value\n})\n\nconst clearValue = () => {\n wrappedValue.value = []\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 py-1 label label--light border border-outline-3 shadow-md 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-40')\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: { disabled: boolean }) => {\n const { disabled } = params\n const classParts = ['relative transition select-none px-2']\n\n if (disabled) {\n classParts.push('opacity-50 cursor-not-allowed')\n } else {\n classParts.push('text-foreground cursor-pointer')\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 void debouncedSearch()\n})\n\nonMounted(() => {\n if (isAsyncSearchMode.value && !props.items.length) {\n void triggerSearch()\n }\n})\n\nconst toggleDropdown = () => {\n if (!isDisabled.value) {\n isOpen.value = !isOpen.value\n }\n}\n\nconst isSelected = (item: SingleItem) => {\n return wrappedValue.value.some((v) => itemKey(v) === itemKey(item))\n}\n\nconst optionsContainer = ref<HTMLDivElement | null>(null)\nconst scrollPosition = ref(0)\n\nconst selectItem = (item: SingleItem, event?: Event) => {\n if (props.disabledItemPredicate?.(item)) return\n event?.stopPropagation()\n\n scrollPosition.value = optionsContainer.value?.scrollTop || 0\n\n const currentValue = wrappedValue.value\n const itemExists = currentValue.some((v) => itemKey(v) === itemKey(item))\n\n wrappedValue.value = itemExists\n ? currentValue.filter((v) => itemKey(v) !== itemKey(item))\n : [...currentValue, item]\n\n void nextTick(() => {\n if (optionsContainer.value) {\n optionsContainer.value.scrollTop = scrollPosition.value\n }\n })\n}\n\nonClickOutside(\n menuEl,\n () => {\n if (isOpen.value) {\n isOpen.value = false\n }\n },\n {\n ignore: [listboxButton]\n }\n)\n\ndefineExpose({ triggerSearch })\n</script>\n","<template>\n <div class=\"flex items-center space-x-2\">\n <HeadlessSwitch\n :id=\"id || name\"\n v-model=\"enabled\"\n :class=\"switchClasses\"\n :name=\"name\"\n :disabled=\"disabled\"\n >\n <span :class=\"sliderClasses\"></span>\n </HeadlessSwitch>\n <label :for=\"id || name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Switch as HeadlessSwitch } from '@headlessui/vue'\nimport { computed } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n showLabel?: boolean\n name: string\n label?: string\n disabled?: boolean\n id?: string\n }>(),\n {\n showLabel: true\n }\n)\n\nconst enabled = defineModel<boolean>()\n\nconst title = computed(() => props.label || props.name)\n\nconst labelClasses = computed(() => {\n const classParts = ['block label-light']\n\n if (!props.showLabel) {\n classParts.push('sr-only')\n }\n\n return classParts.join(' ')\n})\n\nconst switchClasses = computed(() => {\n const classParts = [\n 'relative inline-flex flex-shrink-0 h-[18px] w-[30px] rounded-full',\n 'transition-colors ease-in-out duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary',\n 'cursor-pointer disabled:cursor-not-allowed disabled:opacity-40'\n ]\n\n if (enabled.value) {\n classParts.push('bg-primary')\n } else {\n classParts.push('bg-foreground-3')\n }\n\n return classParts.join(' ')\n})\n\nconst sliderClasses = computed(() => {\n const classParts = [\n 'pointer-events-none inline-block h-3 w-3 rounded-full mt-[3px] ml-[3px]',\n 'ring-0 transition ease-in-out duration-200 bg-foreground-on-primary'\n ]\n\n if (enabled.value) {\n classParts.push('translate-x-[12px]')\n } else {\n classParts.push('translate-x-0')\n }\n\n return classParts.join(' ')\n})\n</script>\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div\n class=\"relative group bg-foundation border border-outline-2 p-2 rounded-lg pr-20\"\n >\n <div\n v-if=\"isMultiline\"\n class=\"relative z-10 text-body-2xs select-all 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-body-2xs text-foreground font-mono select-all\"\n />\n <div class=\"absolute top-3 right-2 flex justify-end items-center\">\n <FormButton\n color=\"outline\"\n size=\"sm\"\n :icon-left=\"\n isIconButton\n ? copied\n ? ClipboardDocumentCheckIcon\n : ClipboardDocumentIcon\n : undefined\n \"\n :hide-text=\"isIconButton\"\n @click=\"handleCopy\"\n >\n {{ copied ? 'Copied' : 'Copy' }}\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 isIconButton?: boolean\n rows?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isMultiline: false\n})\n\nconst emit = defineEmits<{ (e: 'copy', val: string): void }>()\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","<template>\n <div class=\"flex flex-col items-center\">\n <div class=\"flex gap-2\">\n <div v-for=\"(_, index) in digitCount\" :key=\"index\" class=\"w-10\">\n <FormTextInput\n ref=\"inputRefs\"\n v-model=\"digits[index]\"\n class=\"text-center !text-[14px] py-6 !px-2 font-semibold\"\n color=\"foundation\"\n :name=\"`code-${index}`\"\n type=\"text\"\n inputmode=\"numeric\"\n :disabled=\"disabled\"\n :error=\"internalError\"\n :custom-error-message=\"internalError ? ' ' : undefined\"\n maxlength=\"1\"\n size=\"lg\"\n @input=\"onInput(index)\"\n @keydown=\"onKeyDown(index, $event)\"\n @paste=\"onPaste\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, ref, watch } from 'vue'\nimport { FormTextInput } from '~~/src/lib'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n digitCount?: number\n disabled?: boolean\n error?: boolean\n clearErrorOnEdit?: boolean\n }>(),\n {\n digitCount: 6,\n clearErrorOnEdit: true\n }\n)\n\nconst emit = defineEmits(['update:modelValue', 'complete'])\n\nconst inputRefs = ref<Array<HTMLInputElement | null>>([])\nconst digits = ref<string[]>(new Array(props.digitCount).fill('') as string[])\nconst internalError = ref(props.error)\n\nconst onInput = (index: number) => {\n if (props.clearErrorOnEdit) {\n internalError.value = false\n }\n\n digits.value[index] = digits.value[index].replace(/[^0-9]/g, '')\n\n // Move to next input if available\n if (digits.value[index] && index < props.digitCount - 1) {\n inputRefs.value[index + 1]?.focus()\n }\n}\n\nconst onKeyDown = (index: number, event: KeyboardEvent) => {\n if (event.key === 'Backspace' && !digits.value[index] && index > 0) {\n if (props.clearErrorOnEdit) {\n internalError.value = false\n }\n // Move to previous input on backspace if current is empty\n digits.value[index - 1] = ''\n inputRefs.value[index - 1]?.focus()\n } else if (event.key === 'ArrowLeft' && index > 0) {\n // Move to previous input on left arrow\n inputRefs.value[index - 1]?.focus()\n } else if (event.key === 'ArrowRight' && index < props.digitCount - 1) {\n // Move to next input on right arrow\n inputRefs.value[index + 1]?.focus()\n }\n}\n\nconst onPaste = (event: ClipboardEvent) => {\n if (props.clearErrorOnEdit) {\n internalError.value = false\n }\n event.preventDefault()\n const pastedData = event.clipboardData?.getData('text')\n if (!pastedData) return\n\n const numbers = pastedData.replace(/[^0-9]/g, '').split('')\n\n digits.value = [\n ...numbers.slice(0, props.digitCount),\n ...(Array(Math.max(0, props.digitCount - numbers.length)).fill('') as string[])\n ]\n\n // Focus the next empty input or the last input\n const nextEmptyIndex = digits.value.findIndex((d) => !d)\n if (nextEmptyIndex !== -1) {\n inputRefs.value[nextEmptyIndex]?.focus()\n } else {\n inputRefs.value[props.digitCount - 1]?.focus()\n }\n}\n\n// Focus first input on mount\nonMounted(() => {\n if (inputRefs.value[0]) {\n inputRefs.value[0].focus()\n }\n})\n\n// Watch external error prop changes\nwatch(\n () => props.error,\n (newValue) => {\n internalError.value = newValue\n }\n)\n\n// Watch for external value changes\nwatch(\n () => props.modelValue,\n (newValue) => {\n if (newValue) {\n const newDigits = newValue.split('')\n digits.value = [\n ...newDigits,\n ...(Array(props.digitCount - newDigits.length).fill('') as string[])\n ]\n } else {\n digits.value = Array(props.digitCount).fill('') as string[]\n }\n },\n { immediate: true }\n)\n\n// Watch for completion\nwatch(\n digits,\n (newDigits) => {\n const value = newDigits.join('')\n emit('update:modelValue', value)\n\n // Emit complete when all digits are filled\n if (value.length === props.digitCount) {\n emit('complete', value)\n }\n },\n { deep: true }\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 ? '⌘' : '⌃',\n [ModifierKeys.AltOrOpt]: clientOs === OperatingSystem.Mac ? '⌥' : 'Alt',\n [ModifierKeys.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 { useMagicKeys, whenever } 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\nexport type LabelPosition = 'top' | 'left'\n\n/**\n * onKeyDown wrapper that also checks for modifier keys being pressed\n */\nexport function onKeyboardShortcut(\n modifiers: ModifierKeys[],\n key: string,\n callback: () => void\n) {\n const keys = useMagicKeys()\n\n const modifierKeys = modifiers.map((modifier) => {\n switch (modifier) {\n case ModifierKeys.CtrlOrCmd:\n return clientOs === OperatingSystem.Mac ? 'Meta' : 'Control'\n case ModifierKeys.AltOrOpt:\n return 'Alt'\n case ModifierKeys.Shift:\n return 'Shift'\n default:\n return ''\n }\n })\n\n const keyCombination = `${modifierKeys.join('+')}+${key}`\n\n whenever(keys[keyCombination], callback)\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-50\" open @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-400\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n class=\"fixed top-0 left-0 w-full h-full backdrop-blur-xs bg-black/60 dark:bg-neutral-900/60 transition-opacity\"\n />\n </TransitionChild>\n <div class=\"fixed top-0 left-0 z-10 h-screen !h-[100dvh] w-screen\">\n <div\n class=\"flex md:justify-center h-full w-full md:p-6\"\n :class=\"[\n fullscreen === 'none' || fullscreen === 'desktop'\n ? 'p-4 items-center'\n : 'items-end md:items-center'\n ]\"\n >\n <TransitionChild\n as=\"template\"\n enter=\"ease-out duration-5000\"\n :enter-from=\"`md:opacity-0 ${\n fullscreen === 'mobile' || fullscreen === 'all'\n ? 'translate-y-[100%]'\n : 'translate-y-4'\n } md:translate-y-4`\"\n enter-to=\"md:opacity-100 translate-y-0\"\n leave=\"ease-in duration-5000\"\n leave-from=\"md:opacity-100 translate-y-0\"\n :leave-to=\"`md:opacity-0 ${\n fullscreen === 'mobile' || fullscreen === 'all'\n ? 'translate-y-[100%]'\n : 'translate-y-4'\n } md:translate-y-4`\"\n @after-leave=\"$emit('fully-closed')\"\n >\n <DialogPanel\n :class=\"dialogPanelClasses\"\n dialog-panel-classes\n :as=\"isForm ? 'form' : 'div'\"\n @submit.prevent=\"onFormSubmit\"\n >\n <div\n v-if=\"hasTitle\"\n class=\"border-b border-outline-3\"\n :class=\"scrolledFromTop && 'relative z-20 shadow-lg'\"\n >\n <div\n class=\"flex items-center justify-start rounded-t-lg shrink-0 min-h-[2rem] sm:min-h-[3rem] px-6 py-4 truncate text-heading-sm\"\n >\n <div class=\"flex items-center pr-12\">\n <ChevronLeftIcon\n v-if=\"showBackButton\"\n class=\"w-5 h-5 -ml-1 mr-3\"\n @click=\"$emit('back')\"\n />\n <div class=\"w-full truncate\">\n {{ title }}\n <slot name=\"header\" />\n </div>\n </div>\n </div>\n </div>\n\n <!--\n Due to how forms work, if there's no other submit button, on form submission the first button\n will be clicked. This is a workaround to prevent the close button from being that first button.\n https://stackoverflow.com/a/4763911/3194577\n -->\n <button class=\"hidden\" type=\"button\" />\n\n <FormButton\n v-if=\"!hideCloser\"\n color=\"subtle\"\n size=\"sm\"\n class=\"absolute z-20 top-4 right-5 shrink-0 !w-6 !h-6 !p-0\"\n @click=\"open = false\"\n >\n <XMarkIcon class=\"h-6 w-6 text-foreground-2\" />\n </FormButton>\n <div ref=\"slotContainer\" :class=\"slotContainerClasses\" @scroll=\"onScroll\">\n <slot>Put your content here!</slot>\n </div>\n <div\n v-if=\"hasButtons\"\n class=\"relative z-50 flex justify-end px-6 pb-6 space-x-2 shrink-0 bg-foundation-page\"\n :class=\"{\n 'shadow-t pt-6': !scrolledToBottom,\n [buttonsWrapperClasses || '']: true\n }\"\n >\n <template v-if=\"buttons\">\n <FormButton\n v-for=\"(button, index) in buttons\"\n :key=\"button.id || index\"\n v-bind=\"button.props || {}\"\n :disabled=\"button.props?.disabled || button.disabled\"\n :submit=\"button.props?.submit || button.submit\"\n @click=\"($event) => button.onClick?.($event)\"\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, type LayoutDialogButton } from '~~/src/lib'\nimport { XMarkIcon, ChevronLeftIcon } from '@heroicons/vue/24/outline'\nimport { useResizeObserver, type ResizeObserverCallback } from '@vueuse/core'\nimport { computed, ref, useSlots, watch, onUnmounted, type SetupContext } from 'vue'\nimport { throttle } from 'lodash'\nimport { isClient } from '@vueuse/core'\n\ntype MaxWidthValue = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\ntype FullscreenValues = 'mobile' | 'desktop' | 'all' | 'none'\n\nconst emit = defineEmits<{\n (e: 'update:open', v: boolean): void\n (e: 'fully-closed'): void\n (e: 'back'): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n open: boolean\n maxWidth?: MaxWidthValue\n fullscreen?: FullscreenValues\n hideCloser?: boolean\n showBackButton?: boolean\n /**\n * Prevent modal from closing when the user clicks outside of the modal or presses Esc\n */\n preventCloseOnClickOutside?: boolean\n title?: string\n buttons?: Array<LayoutDialogButton>\n /**\n * Extra classes to apply to the button container.\n */\n buttonsWrapperClasses?: string\n /**\n * If set, the modal will be wrapped in a form element and the `onSubmit` callback will be invoked when the user submits the form\n */\n onSubmit?: (e: SubmitEvent) => void\n isTransparent?: boolean\n }>(),\n {\n fullscreen: 'mobile'\n }\n)\n\nconst slots: SetupContext['slots'] = useSlots()\n\nconst scrolledFromTop = ref(false)\nconst scrolledToBottom = ref(true)\nconst slotContainer = ref<HTMLElement | null>(null)\n\nuseResizeObserver(\n slotContainer,\n throttle<ResizeObserverCallback>(() => {\n // Triggering onScroll on size change too so that we don't get stuck with shadows\n // even tho the new content is not scrollable\n onScroll({ target: slotContainer.value })\n }, 60)\n)\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 'xs':\n return 0\n case 'sm':\n return 1\n case 'md':\n return 2\n case 'lg':\n return 3\n case 'xl':\n return 4\n default:\n return 10000\n }\n})\n\nconst widthClasses = computed(() => {\n const classParts: string[] = ['w-full', 'sm:w-full']\n\n if (!isFullscreenDesktop.value) {\n if (maxWidthWeight.value === 0) {\n classParts.push('md:max-w-sm')\n }\n if (maxWidthWeight.value >= 1) {\n classParts.push('md:max-w-lg')\n }\n if (maxWidthWeight.value >= 2) {\n classParts.push('md:max-w-2xl')\n }\n if (maxWidthWeight.value >= 3) {\n classParts.push('lg:max-w-3xl')\n }\n if (maxWidthWeight.value >= 4) {\n classParts.push('xl:max-w-6xl')\n } else {\n classParts.push('md:max-w-2xl')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst isFullscreenDesktop = computed(\n () => props.fullscreen === 'desktop' || props.fullscreen === 'all'\n)\n\nconst dialogPanelClasses = computed(() => {\n const classParts: string[] = [\n 'transform md:rounded-xl text-foreground overflow-hidden transition-all text-left flex flex-col md:h-auto'\n ]\n\n if (!props.isTransparent) {\n classParts.push('bg-foundation-page shadow-xl border border-outline-2')\n }\n\n if (isFullscreenDesktop.value) {\n classParts.push('md:h-full')\n } else {\n classParts.push('md:max-h-[90vh]')\n }\n\n if (props.fullscreen === 'mobile' || props.fullscreen === 'all') {\n classParts.push('max-md:h-[98vh] max-md:!h-[98dvh]')\n }\n\n if (props.fullscreen === 'none' || props.fullscreen === 'desktop') {\n classParts.push('rounded-lg max-h-[90vh]')\n } else {\n classParts.push('rounded-t-lg')\n }\n\n classParts.push(widthClasses.value)\n return classParts.join(' ')\n})\n\nconst slotContainerClasses = computed(() => {\n const classParts: string[] = ['flex-1 simple-scrollbar overflow-y-auto text-body-xs']\n\n if (!props.isTransparent) {\n if (hasTitle.value) {\n classParts.push('px-6 py-4')\n if (isFullscreenDesktop.value) {\n classParts.push('md:p-0')\n }\n } else if (!isFullscreenDesktop.value) {\n classParts.push('px-6 py-4')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst onClose = () => {\n if (props.preventCloseOnClickOutside) return\n open.value = false\n}\n\nconst onFormSubmit = (e: SubmitEvent) => {\n props.onSubmit?.(e)\n}\n\nconst onScroll = throttle((e: { target: EventTarget | null }) => {\n if (!e.target) return\n\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\n// Toggle 'dialog-open' class on <html> to prevent scroll jumping and disable background scroll.\n// This maintains user scroll position when Headless UI dialogs are activated.\nwatch(open, (newValue) => {\n if (isClient) {\n const html = document.documentElement\n if (newValue) {\n html.classList.add('dialog-open')\n } else {\n html.classList.remove('dialog-open')\n }\n }\n})\n\n// Clean up when the component unmounts\nonUnmounted(() => {\n if (isClient) {\n document.documentElement.classList.remove('dialog-open')\n }\n})\n</script>\n\n<style>\nhtml.dialog-open {\n overflow: visible !important;\n}\nhtml.dialog-open body {\n overflow: hidden !important;\n}\n</style>\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 space-x-4 sm:space-x-8 py-2.5 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-heading-sm flex items-center space-x-1 sm:space-x-2 select-none\"\n :class=\"titleClasses\"\n >\n <div v-if=\"$slots.icon || icon\" class=\"h-4 w-4 empty:h-0 empty:w-0\">\n <slot v-if=\"$slots.icon\" name=\"icon\" />\n <Component :is=\"icon\" v-if=\"icon\" class=\"w-full h-full\" />\n </div>\n <span>{{ title }}</span>\n </div>\n <div>\n <ChevronDownIcon\n v-if=\"!button && !alwaysOpen\"\n class=\"w-4 h-4 transition-all duration-400\"\n :class=\"isExpanded && 'rotate-180'\"\n />\n <FormButton\n v-if=\"button\"\n :to=\"button.expandContent ? undefined : button.to\"\n :color=\"button.expandContent && isExpanded ? 'outline' : button.color\"\n :icon-right=\"\n button.expandContent && isExpanded ? undefined : button.iconRight\n \"\n size=\"sm\"\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-300 overflow-hidden\"\n :class=\"[\n allowOverflow && isExpanded ? '!overflow-visible' : '',\n isExpanded ? 'mb-2 mt-1' : '',\n !button && !alwaysOpen ? 'cursor-pointer hover:bg-foundation-page' : ''\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 { PropType, 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'\nimport type { FormButtonStyle } from '~~/src/helpers/form/button'\n\ntype TitleColor = 'default' | 'danger' | 'warning' | 'success' | 'secondary' | '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: FormButtonStyle\n iconRight?: PropAnyComponent | undefined\n onClick?: () => void\n }\n | undefined,\n alwaysOpen: Boolean,\n lazyLoad: {\n type: Boolean,\n default: false\n },\n icon: {\n type: [Function, Object] as PropType<PropAnyComponent>,\n default: undefined\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-page-2')\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 <HeadlessDisclosure 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 </HeadlessDisclosure>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n DisclosureButton,\n Disclosure as HeadlessDisclosure,\n DisclosurePanel\n} 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 = withDefaults(\n defineProps<{\n title: string\n /**\n * HeadlessUI icon component to use\n */\n icon?: PropAnyComponent\n color?: DisclosureColor\n }>(),\n {\n color: 'default'\n }\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'\nimport type { FormButton } from '~~/src/lib'\n\ntype FormButtonProps = InstanceType<typeof FormButton>['$props']\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\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 count?: number\n tag?: string\n icon?: PropAnyComponent\n disabled?: boolean\n disabledMessage?: 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\nexport type LayoutDialogButton = {\n text: string\n props?: Record<string, unknown> & FormButtonProps\n onClick?: (e: MouseEvent) => void\n disabled?: boolean\n disabledMessage?: string\n submit?: boolean\n /**\n * This should uniquely identify the button within the form. Even if you have different sets\n * of buttons rendered on different steps of a wizard, all of them should have unique IDs to\n * ensure proper form functionality.\n */\n id?: string\n}\n\nexport type LayoutTableColours = 'primary' | 'outline' | 'subtle' | 'danger'\n","<template>\n <button\n class=\"max-w-max transition flex justify-center items-center space-x-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.List\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=\"'List View'\"\n class=\"relative z-10 flex space-x-1 items-center p-1 rounded-l\"\n >\n <Bars3Icon class=\"h-5 w-5\" />\n </div>\n <div\n v-tippy=\"'Grid View'\"\n class=\"relative z-10 flex space-x-1 items-center p-1 rounded-r\"\n >\n <Squares2X2Icon 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<{\n (e: 'click', v: MouseEvent): void\n (e: 'update:modelValue', v: GridListToggleValue): void\n}>()\n\nconst props = defineProps<{\n modelValue?: GridListToggleValue\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 <HeadlessMenu v-slot=\"{ open: isMenuOpen }\" as=\"div\" class=\"relative inline-block\">\n <div>\n <MenuButton :id=\"menuId\" 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 ref=\"menuButtonWrapper\" :class=\"isMenuOpen ? 'pointer-events-none' : ''\">\n <slot :toggle=\"toggle\" :open=\"processOpen(isMenuOpen)\" />\n </div>\n </div>\n <Teleport to=\"body\" :disabled=\"!mountMenuOnBody\">\n <MenuItems\n v-if=\"isMenuOpen\"\n ref=\"menuItems\"\n :class=\"[\n 'mt-1 w-44 origin-top-right divide-y divide-outline-3 rounded-md bg-foundation shadow-lg border border-outline-2 z-50',\n menuDirection === HorizontalDirection.Left ? 'right-0' : '',\n mountMenuOnBody ? 'fixed' : 'absolute',\n size === 'lg' ? 'w-52' : 'w-44'\n ]\"\n :style=\"menuItemsStyles\"\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-4 w-4\" />\n <slot name=\"item\" :item=\"item\">{{ item.title }}</slot>\n </button>\n </span>\n </MenuItem>\n </div>\n </MenuItems>\n </Teleport>\n </HeadlessMenu>\n</template>\n\n<script setup lang=\"ts\">\nimport { directive as vTippy } from 'vue-tippy'\nimport { Menu as HeadlessMenu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref, watch, onMounted } from 'vue'\nimport {\n HorizontalDirection,\n useResponsiveHorizontalDirectionCalculation\n} from '~~/src/composables/common/window'\nimport type { LayoutMenuItem } from '~~/src/helpers/layout/components'\nimport { useElementBounding, useEventListener } from '@vueuse/core'\n\nconst emit = defineEmits<{\n (e: 'update:open', val: boolean): void\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (e: 'chosen', val: { event: MouseEvent; item: LayoutMenuItem<any> }): void\n}>()\n\nconst props = defineProps<{\n open?: boolean\n /**\n * 2D array so that items can be grouped with dividers between them\n */\n items: LayoutMenuItem[][]\n size?: 'base' | 'lg'\n menuId?: string\n menuPosition?: HorizontalDirection\n mountMenuOnBody?: boolean\n}>()\n\nconst menuItems = ref(null as Nullable<{ el: HTMLDivElement }>)\nconst menuButton = ref(null as Nullable<{ el: HTMLButtonElement }>)\nconst menuButtonWrapper = ref(null as Nullable<HTMLElement>)\nconst isOpenInternally = ref(false)\nconst isMounted = ref(false)\n\nconst finalOpen = computed({\n get: () => props.open || false,\n set: (newVal) => emit('update:open', newVal)\n})\n\nconst menuButtonBounding = useElementBounding(menuButtonWrapper, {\n windowResize: true,\n windowScroll: true,\n immediate: true\n})\n\nconst menuItemsStyles = computed(() => {\n if (!props.mountMenuOnBody) return {}\n\n if (!menuButtonBounding.width.value) return {}\n let offsetPosition = menuButtonBounding.left.value\n\n if (props.menuPosition === HorizontalDirection.Left) {\n const menuWidth = props.size === 'lg' ? 175 : 143\n offsetPosition = menuButtonBounding.left.value - menuWidth\n }\n\n return {\n position: 'fixed',\n top: `${menuButtonBounding.top.value + menuButtonBounding.height.value}px`,\n left: `${offsetPosition}px`,\n zIndex: 50\n }\n})\n\nconst { direction: calculatedDirection } = useResponsiveHorizontalDirectionCalculation({\n el: computed(() => menuItems.value?.el || null),\n defaultDirection: HorizontalDirection.Left,\n stopUpdatesBelowWidth: 300\n})\n\nconst menuDirection = computed(() => {\n return props.menuPosition || calculatedDirection.value\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 space-x-2 w-full items-center rounded-md px-2 py-1 text-body-xs'\n ]\n\n if (active && !color) {\n classParts.push('bg-primary-muted text-foreground')\n } else if (disabled) {\n classParts.push('opacity-40')\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 = () => {\n menuButton.value?.el.click()\n if (props.mountMenuOnBody) {\n menuButtonBounding.update()\n }\n}\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\nonMounted(() => {\n isMounted.value = true\n})\n\nuseEventListener(window, 'resize', () => {\n menuButtonBounding.update()\n})\n\nuseEventListener(window, 'scroll', () => {\n menuButtonBounding.update()\n})\n</script>\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nexport default trimmedEndIndex;\n","import trimmedEndIndex from './_trimmedEndIndex.js';\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nexport default baseTrim;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseTrim from './_baseTrim.js';\nimport isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nexport default toNumber;\n","import root from './_root.js';\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\nexport default now;\n","import isObject from './isObject.js';\nimport now from './now.js';\nimport toNumber from './toNumber.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n clearTimeout(timerId);\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\nexport default debounce;\n","import debounce from './debounce.js';\nimport isObject from './isObject.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\nexport default throttle;\n","<template>\n <div class=\"relative z-10 flex flex-col !mt-0\">\n <!-- Left Arrow Button -->\n <div\n class=\"absolute left-[-2px] top-[-2px] z-20 pr-8 bg-gradient-to-r from-foundation-page to-transparent\"\n >\n <button\n v-if=\"showLeftArrow\"\n class=\"bg-foundation p-1 rounded-full border border-outline-4 shadow\"\n @click=\"scrollLeft\"\n >\n <ArrowLongLeftIcon class=\"h-4 w-4\" />\n </button>\n </div>\n <div class=\"absolute left-0 z-10 w-full h-[1px] mt-px bg-outline-3 top-8\"></div>\n <div\n ref=\"scrollContainer\"\n class=\"relative overflow-x-auto hide-scrollbar w-full\"\n @scroll=\"handleScroll\"\n >\n <div\n :style=\"borderStyle\"\n class=\"h-[2px] absolute bottom-0 z-20 transition-[left,width] duration-300\"\n :class=\"isInitialSetup ? 'bg-transparent' : 'bg-primary'\"\n ></div>\n\n <div ref=\"buttonContainer\" class=\"flex w-full space-x-4\">\n <button\n v-for=\"item in items\"\n :key=\"item.id\"\n :data-tab-id=\"item.id\"\n :class=\"[\n buttonClass(item),\n { '!border-primary': isActiveItem(item) && isInitialSetup }\n ]\"\n class=\"tab-button\"\n :disabled=\"item.disabled\"\n @click=\"setActiveItem(item)\"\n >\n <div class=\"flex space-x-2 items-center\">\n <component\n :is=\"item.icon\"\n v-if=\"item.icon\"\n class=\"shrink-0 h-4 w-4 stroke-[2px]\"\n />\n\n <div class=\"min-w-6\">\n <span\n v-if=\"item.disabled && item.disabledMessage\"\n v-tippy=\"item.disabledMessage\"\n >\n {{ item.title }}\n </span>\n <span v-else>{{ item.title }}</span>\n </div>\n <div\n v-if=\"item.count\"\n class=\"rounded-full px-2 text-body-3xs transition-all min-w-6\"\n :class=\"\n activeItem?.id === item.id\n ? 'text-primary bg-info-lighter dark:text-foreground'\n : 'text-foreground-2 bg-foundation-2'\n \"\n >\n <span>{{ item.count }}</span>\n </div>\n <CommonBadge v-if=\"item.tag\">\n {{ item.tag }}\n </CommonBadge>\n </div>\n </button>\n </div>\n </div>\n\n <!-- Right Arrow Button -->\n <div\n class=\"absolute right-[-2px] top-[-2px] z-20 pl-8 bg-gradient-to-l from-foundation-page to-transparent\"\n >\n <button\n v-if=\"showRightArrow\"\n class=\"bg-foundation p-1 rounded-full border border-outline-3 shadow\"\n @click=\"scrollRight\"\n >\n <ArrowLongRightIcon class=\"h-4 w-4\" />\n </button>\n </div>\n <div class=\"pt-4\">\n <slot :active-item=\"activeItem\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, onMounted, watch, onBeforeUnmount } from 'vue'\nimport type { CSSProperties } from 'vue'\nimport type { LayoutPageTabItem } from '~~/src/helpers/layout/components'\nimport { isClient } from '@vueuse/core'\nimport { ArrowLongRightIcon, ArrowLongLeftIcon } from '@heroicons/vue/24/outline'\nimport type { Nullable } from '@speckle/shared'\nimport { throttle } from '#lodash'\nimport { useElementSize } from '@vueuse/core'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\n\nconst props = defineProps<{\n items: LayoutPageTabItem[]\n}>()\n\nconst activeItem = defineModel<LayoutPageTabItem>('activeItem', { required: true })\n\nconst buttonContainer = ref(null as Nullable<HTMLDivElement>)\nconst scrollContainer = ref<HTMLElement | null>(null)\nconst showLeftArrow = ref(false)\nconst showRightArrow = ref(false)\nconst isInitialSetup = ref(true)\n\nconst { width } = useElementSize(buttonContainer)\n\nconst buttonClass = computed(() => {\n return (item: LayoutPageTabItem) => {\n const isActive = activeItem.value?.id === item.id\n const baseClasses = [\n 'relative',\n 'z-10',\n 'flex',\n 'items-center',\n 'disabled:opacity-60 disabled:hover:border-transparent disabled:cursor-not-allowed disabled:hover:bg-transparent',\n 'text-body-xs',\n 'hover:sm:border-outline-2',\n 'pb-2',\n 'border-b-[2px]',\n 'border-transparent',\n 'max-w-max',\n 'last:mr-6',\n 'whitespace-nowrap'\n ]\n\n if (isActive) baseClasses.push('text-primary', 'hover:text-primary')\n else baseClasses.push('text-foreground')\n\n return baseClasses\n }\n})\n\nconst activeItemRef = computed(() => {\n const id = activeItem.value?.id\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 HTMLElement[]\n return btns.find((b) => b.dataset['tabId'] === id) || null\n})\n\nconst borderStyle = computed<CSSProperties>(() => {\n // Using width in calculation to force dependency\n return width.value\n ? {\n left: `${activeItemRef.value?.offsetLeft || 0}px`,\n width: `${activeItemRef.value?.clientWidth || 0}px`\n }\n : {\n left: '0px',\n width: '0px'\n }\n})\n\nconst setActiveItem = (item: LayoutPageTabItem) => {\n activeItem.value = item\n isInitialSetup.value = false\n}\n\nconst isActiveItem = (item: LayoutPageTabItem) => {\n return activeItem.value?.id === item.id\n}\n\nconst checkArrowsVisibility = () => {\n const container = scrollContainer.value\n if (!container) return\n\n const scrollWidth = container.scrollWidth\n const clientWidth = container.clientWidth\n const scrollLeft = container.scrollLeft\n const buffer = 1\n\n showLeftArrow.value = scrollLeft > buffer\n showRightArrow.value = scrollLeft < scrollWidth - clientWidth - buffer\n}\n\nconst scrollLeft = () => {\n scrollContainer.value?.scrollBy({ left: -100, behavior: 'smooth' }) // Adjust the scroll amount as needed\n checkArrowsVisibility()\n}\n\nconst scrollRight = () => {\n scrollContainer.value?.scrollBy({ left: 100, behavior: 'smooth' }) // Adjust the scroll amount as needed\n checkArrowsVisibility()\n}\n\nconst handleScroll = throttle(() => {\n checkArrowsVisibility()\n}, 250)\n\nconst ensureActiveItemVisible = () => {\n const activeButton = activeItemRef.value\n if (activeButton && scrollContainer.value) {\n activeButton.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center'\n })\n }\n}\n\nonMounted(() => {\n if (isClient) {\n if (props.items.length && !activeItem.value) {\n setActiveItem(props.items[0])\n }\n checkArrowsVisibility()\n ensureActiveItemVisible()\n }\n})\n\nwatch(\n () => [props.items, activeItem.value] as const,\n ([newItems]) => {\n if (Array.isArray(newItems) && newItems.length && !activeItem.value) {\n setActiveItem(newItems[0])\n }\n checkArrowsVisibility()\n }\n)\n\nonBeforeUnmount(() => {\n handleScroll.cancel()\n})\n</script>\n<style>\n/* Hide scrollbar for Chrome, Safari and Opera */\n.hide-scrollbar::-webkit-scrollbar {\n display: none;\n}\n\n/* Hide scrollbar for IE, Edge and Firefox */\n.hide-scrollbar {\n -ms-overflow-style: none; /* IE and Edge */\n scrollbar-width: none; /* Firefox */\n}\n</style>\n","<template>\n <div class=\"flex space-y-8 lg:space-y-0 lg:space-x-8 flex-col lg:flex-row\">\n <div class=\"lg:w-2/12\">\n <div class=\"flex w-full flex-col space-y-1\">\n <button\n v-for=\"item in items\"\n :key=\"item.id\"\n :data-tab-id=\"item.id\"\n :class=\"[buttonClass(item)]\"\n :disabled=\"item.disabled\"\n @click=\"setActiveItem(item)\"\n >\n <div\n v-tippy=\"\n item.disabled && item.disabledMessage ? item.disabledMessage : undefined\n \"\n class=\"absolute top-0 right-0 left-0 bottom-0\"\n ></div>\n <div class=\"flex space-x-2 items-center px-2\">\n <component\n :is=\"item.icon\"\n v-if=\"item.icon\"\n class=\"shrink-0 h-4 w-4 stroke-[2px]\"\n ></component>\n <span class=\"min-w-6\">{{ item.title }}</span>\n <div\n v-if=\"item.count\"\n class=\"rounded-full px-2 text-body-3xs transition-all min-w-6\"\n :class=\"\n activeItem?.id === item.id\n ? 'text-primary bg-info-lighter dark:text-foreground'\n : 'text-foreground-2 bg-foundation-2'\n \"\n >\n <span>{{ item.count }}</span>\n </div>\n <div\n v-if=\"item.tag\"\n class=\"text-body-3xs font-medium py-0.5 px-1.5 text-foreground-2 bg-foundation-2 uppercase text-outline-4 rounded\"\n >\n {{ item.tag }}\n </div>\n </div>\n </button>\n </div>\n </div>\n\n <div class=\"lg:w-10/12\">\n <slot :active-item=\"activeItem\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, watch } from 'vue'\nimport type { LayoutPageTabItem } from '~~/src/helpers/layout/components'\nimport { isClient } from '@vueuse/core'\n\nconst props = defineProps<{\n items: LayoutPageTabItem[]\n}>()\n\nconst activeItem = defineModel<LayoutPageTabItem>('activeItem', { required: true })\n\nconst buttonClass = computed(() => {\n return (item: LayoutPageTabItem) => {\n const isActive = activeItem.value?.id === item.id\n const baseClasses = [\n 'relative',\n 'flex items-center space-x-1.5',\n 'hover:bg-highlight-2',\n 'disabled:opacity-60 disabled:hover:border-transparent disabled:cursor-not-allowed disabled:hover:bg-transparent rounded-md',\n 'text-body-xs font-medium',\n 'py-1'\n ]\n\n if (isActive) baseClasses.push('bg-primary-muted')\n else baseClasses.push('border-transparent text-foreground')\n\n return baseClasses\n }\n})\n\nconst setActiveItem = (item: LayoutPageTabItem) => {\n activeItem.value = item\n}\n\nonMounted(() => {\n if (isClient) {\n if (props.items.length && !activeItem.value) {\n setActiveItem(props.items[0])\n }\n }\n})\n\nwatch(\n () => [props.items, activeItem.value],\n ([newItems]) => {\n if (Array.isArray(newItems) && newItems.length && !activeItem.value) {\n setActiveItem(newItems[0])\n }\n }\n)\n</script>\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div class=\"text-foreground\">\n <div\n class=\"w-full text-sm overflow-x-auto overflow-y-visible simple-scrollbar border border-outline-3 rounded-lg\"\n >\n <div :class=\"headerRowClasses\" :style=\"{ paddingRight: paddingRightStyle }\">\n <div\n v-for=\"(column, colIndex) in columns\"\n :key=\"column.id\"\n :class=\"getHeaderClasses(column.id, colIndex)\"\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-if=\"loading || !items\"\n class=\"flex items-center justify-center py-3\"\n tabindex=\"0\"\n >\n <CommonLoadingIcon />\n </div>\n <template v-else-if=\"items?.length\">\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\n v-if=\"buttons\"\n class=\"absolute right-1.5 space-x-1 flex items-center p-0 h-full\"\n >\n <div v-for=\"button in buttons\" :key=\"button.label\">\n <FormButton\n v-tippy=\"button.tooltip\"\n :icon-left=\"button.icon\"\n size=\"sm\"\n color=\"outline\"\n hide-text\n :class=\"button.class\"\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 </template>\n <div\n v-else\n tabindex=\"0\"\n :style=\"{ paddingRight: paddingRightStyle }\"\n :class=\"rowsWrapperClasses\"\n >\n <div :class=\"getClasses(undefined, 0)\" tabindex=\"0\">\n <slot name=\"empty\">\n <div class=\"w-full text-center label-light text-foreground-2 italic\">\n {{ emptyMessage }}\n </div>\n </slot>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\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 { CommonLoadingIcon, FormButton } from '~~/src/lib'\nimport { directive as vTippy } from 'vue-tippy'\n\nexport type TableColumn<I> = {\n id: I\n header: string\n classes: string\n}\n\nexport type RowButton<T = unknown> = {\n icon: PropAnyComponent\n label: string\n action: (item: T) => unknown\n class?: string\n tooltip?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[] | undefined | null\n buttons?: RowButton<T>[]\n columns: TableColumn<C>[]\n overflowCells?: boolean\n onRowClick?: (item: T) => void\n rowItemsAlign?: 'center' | 'stretch'\n emptyMessage?: string\n loading?: boolean\n }>(),\n { rowItemsAlign: 'center', emptyMessage: 'No data found' }\n)\n\nconst buttonCount = computed(() => {\n return (props.buttons || []).length\n})\nconst paddingRightStyle = computed(() => {\n let padding = 16\n if (buttonCount.value > 0) {\n padding = 48 + (buttonCount.value - 1) * 42\n }\n return `${padding}px`\n})\n\nconst rowsWrapperClasses = computed(() => {\n const classParts = [\n 'relative grid grid-cols-12 items-center space-x-6 px-4 py-0.5 min-w-[750px] text-body-xs'\n ]\n\n if (props.onRowClick && props.items?.length) {\n classParts.push('cursor-pointer hover:bg-highlight-1')\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 = (\n column: C | undefined,\n colIndex: number,\n options?: Partial<{\n noPadding: boolean\n }>\n): string => {\n const columnClasses = column\n ? props.columns.find((c) => c.id === column)?.classes\n : ''\n const classParts = [columnClasses || '']\n\n if (!options?.noPadding) {\n if (colIndex === 0) {\n classParts.push('px-1')\n } else {\n classParts.push('lg:p-0 px-1')\n }\n }\n\n return classParts.join(' ')\n}\n\nconst getClasses = (\n column: C | undefined,\n colIndex: number,\n options?: Partial<{\n noPadding: boolean\n }>\n): string => {\n const classParts = [getHeaderClasses(column, colIndex, options)]\n\n if (colIndex === 0) {\n classParts.push(`bg-transparent py-2 ${column ? 'pr-5' : 'col-span-full'}`)\n } else {\n classParts.push(`my-2`)\n }\n\n return classParts.join(' ')\n}\n\nconst handleRowClick = (item: T) => {\n props.onRowClick?.(item)\n}\n\nconst headerRowClasses = computed(() => [\n 'z-10 grid grid-cols-12 items-center',\n 'w-full min-w-[750px] space-x-6',\n 'px-4 py-3',\n 'bg-foundation-2 rounded-t-lg',\n 'font-medium text-body-2xs text-foreground-2',\n 'border-b border-outline-3'\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<{\n (e: 'infinite', $state: InfiniteLoaderState): void\n}>()\n\ndefineProps<{\n /**\n * v3-infinite-loading props, see docs or type definitions\n */\n settings?: {\n target?: string\n distance?: number\n top?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n identifier?: any\n firstload?: boolean\n }\n /**\n * Whether to allow retry and show a retry button when loading fails\n */\n allowRetry?: 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 -top-1 -left-1 -right-1 -bottom-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<{ (e: 'submit', val: SubmitEvent): void }>()\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-1 hover:ring-1')\n }\n if (props.panelClasses) {\n classParts.push(props.panelClasses)\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <!-- If promo content is defined, scroll the menu items. If not, scroll the whole aside -->\n <aside\n class=\"flex flex-col justify-between h-full w-full\"\n :class=\"$slots.promo ? '' : 'overflow-y-auto overflow-x-hidden simple-scrollbar'\"\n >\n <div\n class=\"flex flex-col h-full w-full\"\n :class=\"$slots.promo ? 'overflow-y-auto overflow-x-hidden simple-scrollbar' : ''\"\n >\n <slot></slot>\n </div>\n <div v-if=\"$slots.promo\" class=\"shrink-0 pt-2\">\n <slot name=\"promo\"></slot>\n </div>\n </aside>\n</template>\n","<template>\n <nav class=\"flex flex-col space-y-4\">\n <slot></slot>\n </nav>\n</template>\n","<template>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M8 3V13M3 8H13\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </svg>\n</template>\n","<template>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.66748 3.66687H3.00081C2.64719 3.66687 2.30805 3.80735 2.058 4.05739C1.80796 4.30744 1.66748 4.64658 1.66748 5.0002V11.0002C1.66748 11.3538 1.80796 11.693 2.058 11.943C2.30805 12.1931 2.64719 12.3335 3.00081 12.3335H9.00081C9.35443 12.3335 9.69357 12.1931 9.94362 11.943C10.1937 11.693 10.3341 11.3538 10.3341 11.0002V10.3335\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M12.59 3.39007C12.8526 3.12751 13.0001 2.77139 13.0001 2.40007C13.0001 2.02875 12.8526 1.67264 12.59 1.41007C12.3274 1.14751 11.9713 1 11.6 1C11.2287 1 10.8726 1.14751 10.61 1.41007L5 7.00007V9.00007H7L12.59 3.39007Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M9.66748 2.33313L11.6675 4.33313\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n","<template>\n <svg\n width=\"16\"\n height=\"32\"\n viewBox=\"0 0 16 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.64645 17.7498C7.84171 17.9451 8.15829 17.9451 8.35355 17.7498L11.1464 14.9569C11.4614 14.642 11.2383 14.1034 10.7929 14.1034H5.20711C4.76165 14.1034 4.53857 14.642 4.85355 14.9569L7.64645 17.7498Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n","<template>\n <div class=\"flex flex-col group\">\n <div\n v-if=\"title\"\n class=\"h-8 flex items-center justify-between select-none rounded-md\"\n :class=\"[collapsible && !noHover && 'hover:bg-highlight-1']\"\n >\n <component\n :is=\"collapsible ? 'button' : 'div'\"\n class=\"flex items-center w-full\"\n :class=\"[\n collapsible ? 'group rounded-md gap-x-1' : 'space-x-1 p-1 text-foreground-2',\n collapsible && !noHover ? 'py-0.5 px-2' : 'pl-2'\n ]\"\n @click=\"collapsible ? (isCollapsed = !isCollapsed) : undefined\"\n >\n <ArrowFilled\n v-if=\"collapsible\"\n :class=\"[isCollapsed ? '-rotate-90' : '', noHover ? '-ml-1' : '']\"\n class=\"text-foreground-2 shrink-0\"\n />\n <div\n v-if=\"$slots['title-icon']\"\n class=\"flex items-center justify-center\"\n :class=\"[collapsible ? 'ml-1 mr-2' : '']\"\n >\n <slot name=\"title-icon\"></slot>\n </div>\n <div class=\"flex flex-1 items-center truncate justify-between\">\n <h6\n class=\"truncate text-body-2xs pr-2\"\n :class=\"[nested ? 'text-foreground' : 'font-semibold text-foreground-2']\"\n >\n {{ title }}\n </h6>\n <CommonBadge v-if=\"tag\" rounded>\n {{ tag }}\n </CommonBadge>\n </div>\n </component>\n <button\n v-if=\"iconClick\"\n v-tippy=\"iconText ? iconText : undefined\"\n class=\"hidden group-hover:flex p-1 shrink-0 hover:bg-primary-muted rounded text-foreground-2\"\n :class=\"noHover ? '' : 'mr-2'\"\n @click=\"iconClick\"\n >\n <Edit v-if=\"icon === 'edit'\" class=\"h-4 w-4\" />\n <ChevronRightIcon v-else-if=\"icon === 'view'\" class=\"h-4 w-4\" />\n <Plus v-else class=\"h-4 w-4\" />\n </button>\n </div>\n\n <div v-show=\"!isCollapsed\" class=\"flex flex-col\">\n <slot></slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Plus from '~~/src/components/global/icon/Plus.vue'\nimport Edit from '~~/src/components/global/icon/Edit.vue'\nimport ArrowFilled from '~~/src/components/global/icon/ArrowFilled.vue'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\nimport { ChevronRightIcon } from '@heroicons/vue/24/outline'\n\ndefineProps<{\n tag?: string\n title?: string\n collapsible?: boolean\n collapsed?: boolean\n icon?: 'add' | 'edit' | 'view'\n iconText?: string\n iconClick?: () => void\n noHover?: boolean\n nested?: boolean\n}>()\n\nconst isCollapsed = defineModel<boolean>('collapsed')\n</script>\n","<template>\n <div\n v-if=\"!hasChildren\"\n v-tippy=\"tooltipText\"\n :to=\"to\"\n class=\"group/item flex items-center justify-between space-x-2 shrink-0 text-body-xs text-foreground select-none rounded-md w-full py-1\"\n :class=\"[\n !disabled && 'cursor-pointer hover:bg-highlight-1',\n disabled && 'cursor-not-allowed',\n active && 'bg-highlight-3 hover:!bg-highlight-3',\n $slots.icon ? 'pl-1 pr-2' : 'pr-2 pl-7',\n extraPadding && '!pl-14'\n ]\"\n >\n <div\n class=\"flex items-center space-x-2 truncate\"\n :class=\"[disabled && 'opacity-60']\"\n >\n <div v-if=\"$slots.icon\" class=\"h-6 w-6 flex items-center justify-center\">\n <slot name=\"icon\" />\n </div>\n <span class=\"truncate\">\n {{ label }}\n </span>\n <ArrowUpRightIcon\n v-if=\"external\"\n class=\"h-2.5 w-2.5 !stroke-[3px] -ml-1 -mt-1.5 opacity-0 group-hover/item:opacity-100 shrink-0\"\n />\n </div>\n <CommonBadge\n v-if=\"tag\"\n rounded\n :color-classes=\"\n colorClasses ?? (disabled ? 'text-foreground-2 bg-primary-muted' : undefined)\n \"\n >\n {{ tag }}\n </CommonBadge>\n </div>\n <div v-else class=\"flex flex-col\">\n <button\n v-tippy=\"tooltipText\"\n class=\"flex space-x-1.5 items-center w-full rounded-md p-0.5\"\n :class=\"[\n !disabled && 'cursor-pointer text-foreground-2 hover:text-foreground',\n disabled && 'opacity-60'\n ]\"\n @click=\"toggleOpen\"\n >\n <ArrowFilled class=\"h-1 w-2 shrink-0\" :class=\"[isOpen ? '' : '-rotate-90']\" />\n\n <h6 class=\"text-heading-sm flex items-center space-x-1.5\">\n {{ label }}\n </h6>\n </button>\n <div v-show=\"isOpen\" class=\"pl-4\">\n <slot></slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, useSlots, type SetupContext } from 'vue'\nimport ArrowFilled from '~~/src/components/global/icon/ArrowFilled.vue'\nimport { ArrowUpRightIcon } from '@heroicons/vue/24/outline'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\n\nconst props = defineProps<{\n label: string\n to?: string\n tag?: string\n external?: boolean\n disabled?: boolean\n active?: boolean\n tooltipText?: string\n extraPadding?: boolean\n colorClasses?: string\n}>()\n\nconst isOpen = ref(true)\n\nconst slots: SetupContext['slots'] = useSlots()\n\nconst hasChildren = !!slots.default\n\nconst toggleOpen = () => {\n if (!props.disabled) {\n isOpen.value = !isOpen.value\n }\n}\n</script>\n","<template>\n <div :class=\"containerClasses\">\n <div :class=\"subcontainerClasses\">\n <div v-if=\"!hideIcon\">\n <Component :is=\"icon\" :class=\"iconClasses\" aria-hidden=\"true\" />\n </div>\n <div class=\"flex-1\">\n <h3 v-if=\"hasTitle\" :class=\"titleClasses\">\n <slot name=\"title\">Title</slot>\n </h3>\n <div v-if=\"hasDescription\" :class=\"descriptionClasses\">\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>\n <div class=\"flex gap-x-2\">\n <FormButton\n v-for=\"(action, i) in actions || []\"\n :key=\"i\"\n color=\"outline\"\n size=\"sm\"\n :to=\"action.url\"\n :external=\"action.externalUrl || false\"\n :disabled=\"action.disabled || false\"\n @click=\"handleActionClick(action)\"\n >\n {{ action.title }}\n </FormButton>\n </div>\n <div\n v-if=\"withDismiss\"\n class=\"flex\"\n :class=\"[hasDescription ? 'items-start' : 'items-center']\"\n >\n <FormButton type=\"button\" color=\"subtle\" size=\"sm\" @click=\"$emit('dismiss')\">\n Dismiss\n </FormButton>\n </div>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n CheckCircleIcon,\n XCircleIcon,\n InformationCircleIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/24/outline'\nimport { noop } from 'lodash'\nimport { computed, useSlots, type SetupContext } from 'vue'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport type {\n PropAnyComponent,\n AlertAction,\n AlertColor\n} from '~~/src/helpers/common/components'\n\ntype Size = 'default' | 'xs' | '2xs'\n\ndefineEmits<{ (e: 'dismiss'): void }>()\n\nconst props = withDefaults(\n defineProps<{\n color?: AlertColor\n withDismiss?: boolean\n actions?: Array<AlertAction>\n customIcon?: PropAnyComponent\n hideIcon?: boolean\n size?: Size\n }>(),\n {\n color: 'success',\n size: 'default'\n }\n)\n\nconst slots: SetupContext['slots'] = useSlots()\nconst hasDescription = computed(() => !!slots['description'])\nconst hasTitle = computed(() => !!slots['title'])\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 return CheckCircleIcon\n default:\n return InformationCircleIcon\n }\n})\n\nconst containerClasses = computed(() => {\n const classParts: string[] = ['rounded-lg text-foreground border border-outline-2']\n\n switch (props.size) {\n case '2xs':\n case 'xs':\n classParts.push('p-2')\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-lightest')\n break\n case 'info':\n classParts.push('bg-info-lightest')\n break\n case 'danger':\n classParts.push('bg-danger-lightest')\n break\n case 'warning':\n classParts.push('bg-warning-lightest')\n break\n case 'neutral':\n classParts.push('bg-foundation')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst subcontainerClasses = computed(() => {\n const classParts: string[] = ['flex items-center w-full']\n\n switch (props.size) {\n case '2xs':\n case 'xs':\n classParts.push('gap-x-1.5')\n break\n case 'default':\n default:\n classParts.push('gap-x-3')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case '2xs':\n classParts.push('h-4 w-4')\n break\n case 'xs':\n classParts.push('h-5 w-5')\n break\n case 'default':\n default:\n classParts.push('h-6 w-6')\n break\n }\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 dark:text-primary')\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 case 'neutral':\n classParts.push('text-foreground-2')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst titleClasses = computed(() => {\n const classParts: string[] = ['font-medium']\n\n switch (props.size) {\n case '2xs':\n classParts.push('text-body-2xs')\n break\n case 'default':\n default:\n classParts.push('text-body-xs')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst descriptionClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case '2xs':\n classParts.push('text-body-2xs pt-0.5')\n break\n case 'default':\n default:\n classParts.push('text-body-xs')\n break\n }\n\n return classParts.join(' ')\n})\n\nfunction handleActionClick(action: AlertAction) {\n if (action.onClick) {\n action.onClick()\n } else {\n noop()\n }\n}\n</script>\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type MaybeAsync, buildManualPromise } 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\nexport { buildManualPromise }\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\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}\n\nenum ComboboxStates {\n Open,\n Closed\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","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\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-else-if=\"showRequired\"\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 v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">(optional)</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 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 top-0 bottom-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\n v-if=\"helpTipId && !hideHelpTip\"\n :id=\"helpTipId\"\n class=\"mt-2\"\n :class=\"helpTipClasses\"\n >\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<{\n (e: 'update:modelValue', val: Tag[]): void\n (e: 'change', val: { event?: Event; value: Tag[] }): void\n (e: 'clear'): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n name: string\n help?: string\n label?: string\n showLabel?: boolean\n rules?: RuleExpression<Tag[]>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n autoFocus?: boolean\n showClear?: boolean\n showRequired?: boolean\n showOptional?: boolean\n color?: InputColor\n wrapperClasses?: string\n size?: InputSize\n placeholder?: string\n disabled?: boolean\n useLabelInErrors?: boolean\n getAutocompleteItems?: (query: string) => MaybeAsync<Tag[]>\n modelValue?: Tag[]\n }>(),\n {\n size: 'base',\n color: 'page',\n useLabelInErrors: true\n }\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 border-outline-3')\n if (isInputFocused.value) {\n classParts.push('ring-1 ring-outline-3')\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 = async () => {\n isAutocompleteLoading.value = true\n await 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 void 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 void 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 =\n | '2xs'\n | 'xs'\n | 'sm'\n | 'base'\n | 'lg'\n | 'xl'\n | 'xxl'\n | '3xl'\n | '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 '2xs':\n return 'h-4'\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-24'\n case '3xl':\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 '2xs':\n return 'w-4'\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-24'\n case '3xl':\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 '2xs':\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-2xl'\n case '3xl':\n return 'text-3xl'\n case 'editable':\n return 'h1'\n case 'base':\n default:\n return 'text-body-2xs'\n }\n })\n\n const iconClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case '2xs':\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 uppercase transition',\n rounded ? 'rounded-full' : 'rounded-md',\n sizeClasses,\n bgClasses,\n borderClasses,\n hoverClasses,\n activeClasses\n ]\"\n >\n <slot>\n <div\n v-if=\"user?.avatar\"\n v-tippy=\"!hideTooltip ? props.user?.name : undefined\"\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 v-tippy=\"!hideTooltip ? props.user?.name : undefined\"\n :class=\"textClasses\"\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 = withDefaults(\n defineProps<{\n user?: MaybeNullOrUndefined<AvatarUser>\n size?: UserAvatarSize\n hoverEffect?: boolean\n active?: boolean\n noBorder?: boolean\n noBg?: boolean\n hideTooltip?: boolean\n rounded?: boolean\n lightStyle?: boolean\n }>(),\n {\n size: 'base',\n hoverEffect: false,\n user: null,\n rounded: true,\n lightStyle: false\n }\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 if (props.lightStyle) return 'border border-outline-2'\n return 'border-2 border-foundation'\n})\n\nconst bgClasses = computed(() => {\n if (props.noBg) return ''\n if (props.lightStyle) return 'bg-foundation-2'\n return 'bg-info-darker'\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\nconst textClasses = computed(() => {\n if (props.lightStyle) return 'text-foreground-3'\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 visibleUsers\"\n :key=\"user.id || i\"\n :user=\"user\"\n :size=\"size\"\n :hide-tooltip=\"hideTooltips\"\n />\n </div>\n <UserAvatar\n v-if=\"totalHiddenCount\"\n :size=\"size\"\n class=\"select-none\"\n :class=\"{ 'cursor-pointer': !!onHiddenCountClick }\"\n @click=\"onHiddenCountClick && onHiddenCountClick()\"\n >\n +{{ totalHiddenCount }}\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 = withDefaults(\n defineProps<{\n users: AvatarUserWithId[]\n overlap?: boolean\n size?: UserAvatarSize\n maxCount?: number\n hideTooltips?: boolean\n maxAvatars?: number\n onHiddenCountClick?: () => void\n }>(),\n {\n users: () => [],\n overlap: true,\n size: 'base',\n maxCount: undefined,\n hideTooltips: false,\n maxAvatars: undefined,\n onHiddenCountClick: undefined\n }\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 visibleUsers = computed(() => {\n const result = props.users\n const limit = Math.min(props.maxCount ?? Infinity, props.maxAvatars ?? Infinity)\n return result.slice(0, limit)\n})\n\nconst maxAvatarsHiddenCount = computed(() => {\n if (!props.maxAvatars) return 0\n return Math.max(props.users.length - props.maxAvatars, 0)\n})\n\nconst totalHiddenCount = computed(\n () =>\n hiddenItemCount.value + maxCountHiddenItemCount.value + maxAvatarsHiddenCount.value\n)\n</script>\n","<template>\n <svg\n class=\"spinner\"\n :class=\"iconClasses\"\n width=\"32px\"\n height=\"40px\"\n viewBox=\"0 0 66 66\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle\n class=\"path\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"6\"\n stroke-linecap=\"round\"\n cx=\"33\"\n cy=\"33\"\n r=\"30\"\n ></circle>\n </svg>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ntype Size = 'base' | 'sm' | 'lg'\n\nconst props = withDefaults(defineProps<{ loading?: boolean; size?: Size }>(), {\n size: 'base',\n loading: true\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['']\n classParts.push(props.loading ? 'opacity-100' : 'opacity-0')\n\n switch (props.size) {\n case 'base':\n classParts.push('h-5 w-5')\n break\n case 'sm':\n classParts.push('h-4 w-4')\n break\n case 'lg':\n classParts.push('h-8 w-8')\n break\n }\n\n return classParts.join(' ')\n})\n</script>\n\n<style scoped>\n@keyframes rotator {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(270deg);\n }\n}\n\n@keyframes dash {\n 0% {\n stroke-dashoffset: 187;\n }\n 50% {\n stroke-dashoffset: 46.75;\n transform: rotate(135deg);\n }\n 100% {\n stroke-dashoffset: 187;\n transform: rotate(450deg);\n }\n}\n\n.spinner {\n animation: rotator 1.4s linear infinite;\n}\n\n.path {\n stroke-dasharray: 187;\n stroke-dashoffset: 0;\n transform-origin: center;\n animation: dash 1.4s ease-in-out infinite;\n}\n</style>\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 :rounded=\"rounded\"\n @cancel=\"editMode = false\"\n @save=\"onSave\"\n />\n <div v-else class=\"relative group\">\n <img\n v-if=\"!modelAsUser.avatar && defaultImg\"\n :src=\"defaultImg\"\n :alt=\"modelAsUser.name\"\n :class=\"sizeClasses\"\n />\n <UserAvatar\n v-else\n hide-tooltip\n :user=\"modelAsUser\"\n :size=\"size\"\n :light-style=\"lightStyle\"\n :rounded=\"rounded\"\n />\n <div\n class=\"opacity-0 transition-all absolute group-hover:opacity-100 top-0 right-0 left-0 bottom-0 flex items-end justify-center bottom-4\"\n >\n <FormButton\n size=\"sm\"\n :disabled=\"disabled\"\n color=\"outline\"\n @click=\"editMode = true\"\n >\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, toRefs } 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'\nimport { useAvatarSizeClasses } from '~~/src/composables/user/avatar'\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<{\n (e: 'save', newUrl: ModelType): void\n (e: 'update:modelValue', value: ModelType): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: ModelType\n /**\n * Placeholder name that will be used to generate and show initials if no avatar is present\n */\n placeholder: string\n /**\n * Name of the field. Used for validation & form submits\n */\n name: string\n rules?: RuleExpression<ModelType>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n disabled?: boolean\n size?: UserAvatarSize\n defaultImg?: string\n rounded?: boolean\n lightStyle?: boolean\n }>(),\n {\n rounded: true,\n lightStyle: false\n }\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})\nconst { sizeClasses } = useAvatarSizeClasses({ props: toRefs(props) })\n\nconst editMode = defineModel<boolean>('editMode')\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\">\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<{\n (e: 'files-selected', v: { files: UploadableFileItem[] }): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n /**\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept\n */\n accept?: string\n /**\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/multiple\n */\n multiple?: boolean\n /**\n * Max file size in bytes\n */\n sizeLimit?: number\n /**\n * Max file count if 'multiple' is set\n */\n countLimit?: number\n disabled?: boolean\n }>(),\n {\n sizeLimit: 1024 * 1024 * 100 // 100mb\n }\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","import type { Optional } from '@speckle/shared'\nimport type { Directive } from 'vue'\n\nconst keyboardClickableKeypressHandler = (e: KeyboardEvent) => {\n if (e.code !== 'Enter') return\n ;(e.target as Optional<HTMLElement>)?.click()\n}\n\n/**\n * Makes it possible to navigate to and click on the element using the keyboard\n */\nexport const vKeyboardClickable: Directive<HTMLElement> = {\n created(el) {\n el.setAttribute('tabindex', '0')\n el.addEventListener('keypress', keyboardClickableKeypressHandler)\n },\n unmounted(el) {\n el.removeEventListener('keypress', keyboardClickableKeypressHandler)\n }\n}\n","<template>\n <div class=\"relative w-full bg-outline-3 rounded h-1.5 overflow-hidden\">\n <div\n class=\"aboslute left-0 top-0 rounded h-1.5\"\n :class=\"colorClass\"\n :style=\"{ width: `${percentage <= 100 ? percentage : 100}%` }\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n currentValue: number\n maxValue: number\n}>()\n\nconst percentage = computed(() => (props.currentValue / props.maxValue) * 100)\nconst colorClass = computed(() => {\n if (percentage.value >= 100) {\n return 'bg-danger'\n }\n if (percentage.value >= 80) {\n return 'bg-warning'\n }\n\n return 'bg-success'\n})\n</script>\n"],"names":["emit","__emit","props","__props","NuxtLink","resolveDynamicComponent","RouterLink","linkComponent","computed","isObjectLike","buttonType","isDisabled","finalLeftIcon","CommonLoadingIcon","bgAndBorderClasses","classParts","colorsBgBorder","sizeClasses","paddingClasses","hasIconLeft","hasIconRight","hideText","generalClasses","baseClasses","additionalClasses","buttonClasses","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","_sfc_render","_ctx","_cache","_openBlock","_createElementBlock","_createElementVNode","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","checkboxClasses","onChange","newModelValue","newCoreValue","shouldBeChecked","isCoreChecked","radioValue","selected","_useModel","selectItem","titleClasses","useTextInputCore","inputEl","options","veeErrorMessage","unref","coreInputClasses","coreClasses","hasError","color","internalHelpTipId","base","hideHelpTip","helpTip","hasHelpTip","customHelpTipClass","helpTipId","helpTipClasses","shouldShowClear","focus","clear","isArray","useDebouncedTextInput","debouncedBy","isBasicHtmlInput","submitOnEnter","log","isBoolean","noop","model","getValue","val","isString","target","debouncedValueUpdate","debounce","inputEventName","on","isUndefined","bind","watch","oldVal","inputElement","computedWrapperClasses","__expose","slots","useSlots","leadingIconClasses","onRightIconClick","VALID_HTTP_URL","VALID_EMAIL","isEmail","isEmailOrEmpty","isOneOrMultipleEmails","i","isRequired","isSameAs","otherFieldName","otherFieldDisplayName","meta","isStringOfLength","minLength","maxLength","isNullOrUndefined","stringContains","match","message","isUrl","isItemSelected","isMultiItemSelected","useWrappingContainerHiddenCount","skipCalculation","elementToWatchForChanges","itemContainer","trackResize","trackMutations","hiddenItemCount","recalculate","avatarElements","visibleCount","totalCount","firstElOffsetTop","avatarEl","offsetTop","useResizeObserver","useMutationObserver","useFormSelectChildInternals","dynamicVisibility","selectedValue","currentValue","isArrayValue","v","mounted","useMounted","showBar","isObjectLikeType","error","isMounted","searchInput","menuEl","listboxButton","searchValue","currentItems","isAsyncLoading","forceUpdateKey","isOpen","listboxButtonBounding","useElementBounding","useIntersectionObserver","isIntersecting","isLeftLabelPosition","renderClearButton","buttonsWrapperClasses","commonButtonClasses","clearButtonClasses","hasValueSelected","hasSearch","isAsyncSearchMode","wrappedValue","finalValue","currentVal","itemKey","clearValue","finalItems","searchVal","listboxOptionsClasses","listboxOptionsStyle","style","top","left","width","height","simpleDisplayText","triggerSearch","debouncedSearch","listboxOptionClasses","disabled","newItems","hiddenSelectedItemCount","isMultiItemArrayValue","firstItem","searchFilterPredicate","search","deselectItem","item","toggleDropdown","isSelected","optionsContainer","scrollPosition","event","itemExists","nextTick","onClickOutside","enabled","switchClasses","sliderClasses","copy","useClipboard","copied","handleCopy","selectAllText","textElement","selection","range","inputRefs","digits","internalError","onInput","index","onKeyDown","onPaste","pastedData","numbers","nextEmptyIndex","d","newValue","newDigits","ModifierKeys","clientOs","getClientOperatingSystem","ModifierKeyTitles","OperatingSystem","getKeyboardShortcutTitle","keys","isModifierKey","k","onKeyboardShortcut","modifiers","key","callback","useMagicKeys","keyCombination","modifier","whenever","useFormCheckboxModel","isChecked","scrolledFromTop","scrolledToBottom","slotContainer","throttle","onScroll","isForm","hasButtons","hasTitle","open","maxWidthWeight","widthClasses","isFullscreenDesktop","dialogPanelClasses","slotContainerClasses","onClose","onFormSubmit","scrollTop","offsetHeight","scrollHeight","isClient","html","onUnmounted","content","contentHeight","isExpanded","backgroundClass","toggleExpansion","panelClasses","GridListToggleValue","ThrottleOrDebounce","ThrottleOrDebounce2","HorizontalDirection","HorizontalDirection2","useWindowResizeHandler","handler","throttleOrDebounce","finalHandler","useOnBeforeWindowUnload","useResponsiveHorizontalDirectionCalculation","el","defaultDirection","direction","stopUpdatesBelowWidth","element","recalculateDirection","rect","showOnLeftSide","showOnRightSide","menuItems","menuButton","menuButtonWrapper","isOpenInternally","finalOpen","menuButtonBounding","menuItemsStyles","offsetPosition","menuWidth","calculatedDirection","menuDirection","buildButtonClassses","active","chooseItem","toggle","processOpen","shouldBeOpen","useEventListener","freeGlobal","freeGlobal$1","freeSelf","root","root$1","Symbol","Symbol$2","objectProto","hasOwnProperty","nativeObjectToString","symToStringTag","getRawTag","isOwn","tag","unmasked","result","objectToString","nullTag","undefinedTag","baseGetTag","symbolTag","isSymbol","reWhitespace","trimmedEndIndex","string","reTrimStart","baseTrim","isObject","type","NAN","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","toNumber","other","isBinary","now","now$1","FUNC_ERROR_TEXT","nativeMax","nativeMin","func","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","args","thisArg","leadingEdge","timerExpired","remainingWait","timeSinceLastCall","timeSinceLastInvoke","timeWaiting","shouldInvoke","trailingEdge","cancel","flush","debounced","isInvoking","activeItem","buttonContainer","scrollContainer","showLeftArrow","showRightArrow","isInitialSetup","useElementSize","buttonClass","isActive","activeItemRef","id","parent","b","borderStyle","setActiveItem","isActiveItem","checkArrowsVisibility","container","scrollWidth","clientWidth","scrollLeft","buffer","scrollRight","handleScroll","ensureActiveItemVisible","activeButton","buttonCount","paddingRightStyle","padding","rowsWrapperClasses","getHeaderClasses","column","colIndex","c","getClasses","handleRowClick","headerRowClasses","wrapper","initializeLoader","int","secondarySlotPaddingClasses","defaultSlotPaddingClasses","$slots","isCollapsed","hasChildren","toggleOpen","hasDescription","icon","InformationCircleIcon","ExclamationCircleIcon","XCircleIcon","CheckCircleIcon","containerClasses","subcontainerClasses","handleActionClick","writableAsyncComputed","get","initialState","readOptions","set","asyncRead","debugging","logSettings","getTrace","logger","finalGet","res","finalSet","readValue","computedAsync","getter","provides","getCurrentInstance","ctxKey","s","state","inject","isInputEvent","isInputFocused","useFocus","ctxManager","autocompleteItems","isAutocompleteLoading","isAutocompleteOpen","query","selectedItems","uniq","t","inputWrapperClasses","removeTag","idx","newSelected","onQueryEscape","onQueryBackspace","newTags","onQueryArrowUp","onQueryArrowDown","resolveAutocompleteItems","debouncedResolve","debouncedResolveAndMarkLoading","onQueryInput","forceCreateFromInput","newTag","tagExists","newIsOpen","oldIsOpen","useAvatarSizeClasses","heightClasses","textClasses","initials","parts","firstLetter","secondLetter","_d","borderClasses","bgClasses","hoverClasses","activeClasses","maxCountHiddenItemCount","visibleUsers","limit","maxAvatarsHiddenCount","totalHiddenCount","LazyUserAvatarEditor","defineAsyncComponent","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","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","keyboardClickableKeypressHandler","vKeyboardClickable","percentage","colorClass"],"mappings":"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","x_google_ignoreList":[40,41,42,43,44,45,46,47,48,49,50,51,52,53,54]}
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/components/form/RadioGroup.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/common/loading/Bar.vue","../src/components/form/select/Base.vue","../src/components/form/select/SourceApps.vue","../src/components/form/select/Badges.vue","../src/components/form/select/Multi.vue","../src/components/form/Switch.vue","../src/components/form/ClipboardInput.vue","../src/components/form/CodeInput.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","../node_modules/lodash-es/_freeGlobal.js","../node_modules/lodash-es/_root.js","../node_modules/lodash-es/_Symbol.js","../node_modules/lodash-es/_getRawTag.js","../node_modules/lodash-es/_objectToString.js","../node_modules/lodash-es/_baseGetTag.js","../node_modules/lodash-es/isObjectLike.js","../node_modules/lodash-es/isSymbol.js","../node_modules/lodash-es/_trimmedEndIndex.js","../node_modules/lodash-es/_baseTrim.js","../node_modules/lodash-es/isObject.js","../node_modules/lodash-es/toNumber.js","../node_modules/lodash-es/now.js","../node_modules/lodash-es/debounce.js","../node_modules/lodash-es/throttle.js","../src/components/layout/tabs/Horizontal.vue","../src/components/layout/tabs/Vertical.vue","../src/components/layout/Table.vue","../src/components/InfiniteLoading.vue","../src/components/layout/Panel.vue","../src/components/layout/sidebar/Sidebar.vue","../src/components/layout/sidebar/menu/Menu.vue","../src/components/global/icon/Plus.vue","../src/components/global/icon/Edit.vue","../src/components/global/icon/ArrowFilled.vue","../src/components/layout/sidebar/menu/group/Group.vue","../src/components/layout/sidebar/menu/group/Item.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","../src/directives/accessibility.ts","../src/components/common/ProgressBar.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 :style=\"\n color !== 'subtle' && !text\n ? `box-shadow: -1px 1px 4px 0px #0000000a inset; box-shadow: 0px 2px 2px 0px #0000000d;`\n : ''\n \"\n @click=\"onClick\"\n >\n <Component :is=\"finalLeftIcon\" v-if=\"finalLeftIcon\" :class=\"iconClasses\" />\n <slot v-if=\"!hideText\">Button</slot>\n <Component :is=\"iconRight\" v-if=\"iconRight || !loading\" :class=\"iconClasses\" />\n </Component>\n</template>\n<script setup lang=\"ts\">\nimport { isObjectLike } from 'lodash'\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\nimport { computed, resolveDynamicComponent } from 'vue'\nimport type { Nullable } from '@speckle/shared'\nimport type { FormButtonStyle, FormButtonSize } from '~~/src/helpers/form/button'\nimport { CommonLoadingIcon } from '~~/src/lib'\n\nconst emit = defineEmits<{\n /**\n * Emit MouseEvent on click\n */\n (e: 'click', val: MouseEvent): void\n}>()\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?: string\n /**\n * Choose from one of 3 button sizes\n */\n size?: FormButtonSize\n /**\n * If set, will make the button take up all available space horizontally\n */\n fullWidth?: boolean\n /**\n * Similar to \"link\", but without an underline and possibly in different colors\n */\n text?: boolean\n /**\n * Will remove paddings and background. Use for links.\n */\n link?: boolean\n /**\n * color:\n * primary: the default primary blue.\n * outline: foundation background and outline\n * subtle: no styling\n */\n color?: FormButtonStyle\n /**\n * Should rounded-full be added?:\n */\n rounded?: boolean\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?: boolean\n /**\n * Whether to disable the button so that it can't be pressed\n */\n disabled?: boolean\n /**\n * If set, will have type set to \"submit\" to enable it to submit any parent forms\n */\n submit?: boolean\n /**\n * Add icon to the left from the text\n */\n iconLeft?: Nullable<PropAnyComponent>\n /**\n * Add icon to the right from the text\n */\n iconRight?: Nullable<PropAnyComponent>\n /**\n * Hide default slot (when you want to show icons only)\n */\n hideText?: boolean\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?: Nullable<PropAnyComponent>\n /**\n * Disables the button and shows a spinning loader\n */\n loading?: boolean\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(() =>\n props.loading ? CommonLoadingIcon : props.iconLeft\n)\n\nconst bgAndBorderClasses = computed(() => {\n const classParts: string[] = []\n\n const colorsBgBorder = {\n subtle: [\n 'bg-transparent border-transparent text-foreground font-medium',\n 'hover:bg-primary-muted disabled:hover:bg-transparent focus-visible:border-foundation'\n ],\n outline: [\n 'bg-foundation border-outline-2 text-foreground font-medium',\n 'hover:bg-primary-muted disabled:hover:bg-foundation focus-visible:border-foundation'\n ],\n danger: [\n 'bg-danger border-danger-darker text-foundation font-medium',\n 'hover:bg-danger-darker disabled:hover:bg-danger focus-visible:border-foundation'\n ],\n primary: [\n 'bg-primary border-outline-1 text-foreground-on-primary font-semibold',\n 'hover:bg-primary-focus disabled:hover:bg-primary focus-visible:border-foundation'\n ]\n }\n\n if (props.rounded) {\n classParts.push('!rounded-full')\n }\n\n if (props.text || props.link) {\n switch (props.color) {\n case 'subtle':\n classParts.push('text-foreground')\n break\n case 'outline':\n classParts.push('text-foreground')\n break\n case 'danger':\n classParts.push('text-danger')\n break\n case 'primary':\n default:\n classParts.push('text-primary')\n break\n }\n } else {\n switch (props.color) {\n case 'subtle':\n classParts.push(...colorsBgBorder.subtle)\n break\n case 'outline':\n classParts.push(...colorsBgBorder.outline)\n break\n case 'danger':\n classParts.push(...colorsBgBorder.danger)\n break\n case 'primary':\n default:\n classParts.push(...colorsBgBorder.primary)\n break\n }\n }\n\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed(() => {\n switch (props.size) {\n case 'sm':\n return 'h-6 text-body-2xs'\n case 'lg':\n return 'h-10 text-body-sm'\n default:\n case 'base':\n return 'h-8 text-body-xs'\n }\n})\n\nconst paddingClasses = computed(() => {\n if (props.text || props.link) {\n return 'p-0'\n }\n\n const hasIconLeft = !!props.iconLeft\n const hasIconRight = !!props.iconRight\n const hideText = props.hideText\n\n switch (props.size) {\n case 'sm':\n if (hideText) return 'w-6'\n if (hasIconLeft) return 'py-1 pr-2 pl-1'\n if (hasIconRight) return 'py-1 pl-2 pr-1'\n return 'px-2 py-1'\n case 'lg':\n if (hideText) return 'w-10'\n if (hasIconLeft) return 'py-2 pr-6 pl-4'\n if (hasIconRight) return 'py-2 pl-6 pr-4'\n return 'px-6 py-2'\n case 'base':\n default:\n if (hideText) return 'w-8'\n if (hasIconLeft) return 'py-0 pr-4 pl-2'\n if (hasIconRight) return 'py-0 pl-4 pr-2'\n return 'px-4 py-0'\n }\n})\n\nconst generalClasses = computed(() => {\n const baseClasses = [\n 'inline-flex justify-center items-center',\n 'text-center select-none whitespace-nowrap',\n 'outline outline-2 outline-transparent',\n 'transition duration-200 ease-in-out focus-visible:outline-outline-4'\n ]\n\n const additionalClasses = []\n\n if (!props.text && !props.link) {\n additionalClasses.push('rounded-md border')\n }\n\n if (props.fullWidth) {\n additionalClasses.push('w-full')\n } else if (!props.hideText) {\n additionalClasses.push('max-w-max')\n }\n if (isDisabled.value) {\n additionalClasses.push('cursor-not-allowed opacity-60')\n }\n\n return [...baseClasses, ...additionalClasses].join(' ')\n})\n\nconst buttonClasses = computed(() => {\n return [\n generalClasses.value,\n sizeClasses.value,\n bgAndBorderClasses.value,\n paddingClasses.value\n ].join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['shrink-0']\n\n switch (props.size) {\n case 'sm':\n classParts.push('h-4 w-4 p-0.5')\n break\n case 'lg':\n classParts.push('h-6 w-6 p-1')\n break\n case 'base':\n default:\n classParts.push('h-6 w-6 p-1')\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","<template>\n <FormButton\n :link=\"underline\"\n :text=\"!underline\"\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 = 'sm' | 'base' | 'lg'\nconst emit = defineEmits<{ (e: 'click', val: MouseEvent): void }>()\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 underline: {\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 Loading\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 id?: string\n}\n","<template>\n <div\n aria-live=\"assertive\"\n class=\"pointer-events-none fixed top-0 right-0 left-0 bottom-0 flex items-end px-4 py-6 mt-10 sm:items-start sm:p-6 z-[60]\"\n >\n <div class=\"flex w-full flex-col items-center space-y-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 bg-foundation text-foreground shadow-lg border border-outline-2 p-3\"\n :class=\"{ 'pb-2': isTitleOnly }\"\n >\n <div class=\"flex space-x-2\">\n <div class=\"flex-shrink-0 mt-1\">\n <CheckCircleIcon\n v-if=\"notification.type === ToastNotificationType.Success\"\n class=\"text-success h-4 w-4\"\n aria-hidden=\"true\"\n />\n <XCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Danger\"\n class=\"text-danger h-4 w-4\"\n aria-hidden=\"true\"\n />\n <ExclamationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Warning\"\n class=\"text-foreground-2 h-4 w-4\"\n aria-hidden=\"true\"\n />\n <InformationCircleIcon\n v-else-if=\"notification.type === ToastNotificationType.Info\"\n class=\"text-foreground-2 h-4 w-4\"\n aria-hidden=\"true\"\n />\n <CommonLoadingIcon\n v-else-if=\"notification.type === ToastNotificationType.Loading\"\n class=\"h-4 w-4 opacity-80\"\n />\n </div>\n <div class=\"w-full min-w-[10rem]\">\n <p\n v-if=\"notification.title\"\n class=\"text-foreground-2 font-medium text-body-xs\"\n >\n {{ notification.title }}\n </p>\n <p\n v-if=\"notification.description\"\n class=\"text-foreground-2 text-body-xs leading-snug\"\n >\n {{ notification.description }}\n </p>\n <div v-if=\"notification.cta\">\n <TextLink\n class=\"mt-1 color-primary\"\n :to=\"notification.cta.url\"\n size=\"sm\"\n @click=\"onCtaClick\"\n >\n {{ notification.cta.title }}\n </TextLink>\n </div>\n </div>\n <div class=\"ml-2 flex-shrink-0 mt-0.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 TextLink from '~~/src/components/common/text/Link.vue'\nimport {\n CheckCircleIcon,\n XCircleIcon,\n ExclamationCircleIcon,\n InformationCircleIcon,\n XMarkIcon\n} from '@heroicons/vue/20/solid'\nimport { computed } from 'vue'\nimport type { MaybeNullOrUndefined } from '@speckle/shared'\nimport { ToastNotificationType } from '~~/src/helpers/global/toast'\nimport type { ToastNotification } from '~~/src/helpers/global/toast'\nimport { CommonLoadingIcon } from '~~/src/lib'\n\nconst emit = defineEmits<{\n (e: 'update:notification', val: MaybeNullOrUndefined<ToastNotification>): void\n}>()\n\nconst props = defineProps<{\n notification: MaybeNullOrUndefined<ToastNotification>\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 * @deprecated Use vKeyboardClickable directive instead\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 <span class=\"whitespace-nowrap\">\n <slot>Badge</slot>\n </span>\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'\ntype BadgeColors = 'primary' | 'secondary'\n\nconst emit = defineEmits<{\n (e: 'click-icon', v: MouseEvent): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n size?: BadgeSize\n color?: BadgeColors\n /**\n * Set text & bg color. Defaults to primary variation.\n */\n colorClasses?: string\n\n /**\n * Show dot to the right\n */\n dot?: boolean\n\n /**\n * Set dot/icon bg color. Defaults to primary variation.\n */\n dotIconColorClasses?: string\n\n /**\n * Optionally show icon to the left of the text\n */\n iconLeft?: PropAnyComponent\n\n /**\n * A more square, but still rounded look\n */\n rounded?: boolean\n\n /**\n * Track icon clicks\n */\n clickableIcon?: boolean\n }>(),\n {\n size: 'base',\n color: 'primary'\n }\n)\n\nconst badgeColorClasses = computed(() => {\n if (props.colorClasses) {\n return props.colorClasses\n } else if (props.color === 'secondary') {\n return 'bg-highlight-3 text-foreground-2'\n } else {\n return 'bg-info-lighter text-primary-focus dark:text-foreground'\n }\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 select-none',\n badgeColorClasses.value,\n props.size === 'lg'\n ? 'px-3 py-0.5 text-body-2xs'\n : 'p-1 text-body-3xs text-body-3xs font-medium'\n ]\n\n if (props.rounded) {\n classParts.push('rounded')\n classParts.push(\n props.size === 'lg'\n ? 'px-2 py-0.5 text-body-2xs'\n : 'px-1.1 py-0.5 text-body-3xs font-medium'\n )\n } else {\n classParts.push('rounded-full')\n classParts.push(\n props.size === 'lg'\n ? 'px-2.5 py-0.5 text-body-2xs'\n : 'px-2.5 py-0.5 text-body-3xs 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 = 768,\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-6'\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-6',\n 'md:space-x-6',\n 'lg:space-x-6',\n 'xl:space-x-6',\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 class=\"flex space-x-2 items-center\">\n <div\n class=\"shrink-0 h-7 w-7 rounded-full border border-primary text-white bg-primary inline-flex items-center justify-center select-none\"\n >\n <CheckIcon class=\"w-4 h-4\" />\n </div>\n <div class=\"flex flex-col\">\n <div class=\"text-body-xs font-medium text-primary\">{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"text-body-2xs text-foreground-2\">\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 class=\"flex space-x-2 items-center\">\n <div\n class=\"shrink-0 h-7 w-7 text-body-xs rounded-full border border-primary inline-flex items-center justify-center select-none text-primary\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div class=\"text-body-xs font-medium text-primary\">{{ step.name }}</div>\n <div v-if=\"step.description\" class=\"text-body-2xs text-foreground-2\">\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 class=\"flex space-x-2 items-center\">\n <div\n class=\"shrink-0 h-7 w-7 rounded-full border border-foreground-3 inline-flex items-center justify-center select-none text-foreground-3\"\n >\n {{ getStepDisplayValue(i) }}\n </div>\n <div class=\"flex flex-col\">\n <div class=\"text-body-xs font-medium text-foreground-2\">\n {{ step.name }}\n </div>\n <div v-if=\"step.description\" class=\"text-body-2xs text-foreground-2\">\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<{\n (e: 'update:modelValue', val: number): void\n}>()\n\nconst props = defineProps<{\n ariaLabel?: string\n orientation?: HorizontalOrVertical\n steps: NumberStepType[]\n modelValue?: number\n goVerticalBelow?: TailwindBreakpoints\n nonInteractive?: boolean\n stepsPadding?: StepsPadding\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<{\n (e: 'update:modelValue', val: number): void\n}>()\n\nconst props = defineProps<{\n ariaLabel?: string\n basic?: boolean\n orientation?: HorizontalOrVertical\n steps: BulletStepType[]\n modelValue?: number\n goVerticalBelow?: TailwindBreakpoints\n nonInteractive?: boolean\n stepsPadding?: StepsPadding\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 top-0 left-0 right-0 bottom-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)\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 void 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<{\n (e: 'update:modelValue', v: boolean): void\n (e: 'click', v: MouseEvent): void\n}>()\n\nconst props = defineProps<{\n disabled?: boolean\n modelValue?: 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\n class=\"relative flex\"\n :class=\"labelPosition === 'left' ? 'flex-row-reverse items-center' : 'items-start'\"\n >\n <div\n class=\"flex h-6 items-center\"\n :class=\"labelPosition === 'left' ? 'w-1/2 justify-end mr-2' : ''\"\n >\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=\"checkboxClasses\"\n v-bind=\"$attrs\"\n @change=\"onChange\"\n />\n </div>\n <div class=\"text-sm\" :class=\"labelPosition === 'left' ? 'w-1/2' : 'ml-2'\">\n <label :for=\"finalId\" :class=\"{ 'sr-only': hideLabel }\">\n <span class=\"text-body-xs text-foreground font-medium\">{{ title }}</span>\n <span v-if=\"showRequired\" class=\"text-danger ml-1\">*</span>\n <p v-if=\"descriptionText\" :id=\"descriptionId\" :class=\"descriptionClasses\">\n {{ descriptionText }}\n </p>\n </label>\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'\nimport type { LabelPosition } from '~~/src/composables/form/input'\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 labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits<{\n (e: 'update:modelValue', val: ValueType): void\n}>()\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 descriptionText = computed(() => props.description || errorMessage.value)\nconst descriptionId = computed(() => `${props.name}-description`)\nconst descriptionClasses = computed((): string => {\n const classParts: string[] = ['text-body-2xs']\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 checkboxClasses = computed(() => {\n const classParts = [\n 'h-3.5 w-3.5 rounded',\n 'border bg-foundation text-primary',\n 'hover:border-foreground-2 focus:ring-1 focus:ring-outline-4 focus:ring-offset-1',\n 'disabled:cursor-not-allowed disabled:opacity-60'\n ]\n\n if (errorMessage.value) {\n classParts.push('border-danger-lighter')\n } else {\n classParts.push('border-outline-5')\n }\n\n return classParts.join(' ')\n})\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 space-x-2 mb-2 last:mb-0\"\n :class=\"description && inlineDescription ? 'items-start' : 'items-center'\"\n >\n <div class=\"flex items-center\" :class=\"size === 'sm' ? 'h-4' : 'h-6'\">\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=\"[\n inlineDescription ? 'flex space-x-2 items-center' : '',\n size === 'sm' ? 'text-body-2xs' : 'text-body-xs'\n ]\"\n >\n <label\n :for=\"finalId\"\n class=\"text-foreground flex space-x-2 items-center\"\n :class=\"{ 'sr-only': hideLabel }\"\n >\n <div v-if=\"icon\">\n <component\n :is=\"icon\"\n :class=\"[\n size === 'sm' ? 'h-6 sm:h-8 w-6 sm:w-8' : 'h-8 w-8 sm:h-10 sm:w-10'\n ]\"\n />\n </div>\n <div class=\"flex flex-col\">\n <span class=\"font-medium\">{{ 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[]\ntype Size = 'sm' | 'base'\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 size: {\n type: String as PropType<Optional<Size>>,\n default: 'base'\n }\n})\n\nconst generateRandomId = (prefix: string) => `${prefix}-${nanoid()}`\n\ndefineEmits<{\n (e: 'update:modelValue', val: ValueType): void\n}>()\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-body-3xs']\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","<template>\n <div class=\"w-full\">\n <div\n class=\"flex items-stretch w-full\"\n :class=\"\n isStacked\n ? 'flex-col space-y-3 '\n : 'flex-col sm:flex-row space-y-3 sm:space-y-0 sm:space-x-3'\n \"\n >\n <div v-for=\"option in options\" :key=\"option.value\" class=\"w-full flex flex-col\">\n <button\n class=\"bg-foundation relative w-full h-full select-none rounded-md border shadow\"\n :class=\"[\n selected === option.value ? 'border-outline-4' : 'border-outline-2',\n disabled ? 'opacity-60 cursor-not-allowed' : 'hover:border-outline-1'\n ]\"\n :disabled=\"disabled\"\n @click=\"selectItem(option.value)\"\n >\n <div class=\"p-4 flex flex-col space-y-2 h-full\">\n <div\n class=\"flex justify-between gap-x-3\"\n :class=\"option.icon ? 'items-start' : 'items-center'\"\n >\n <div class=\"flex flex-1 items-start text-left gap-x-2\">\n <component\n :is=\"option.icon\"\n v-if=\"option.icon\"\n class=\"text-foreground h-8 w-8 -mt-1 stroke-[1px]\"\n />\n <div class=\"flex flex-col\">\n <h4 :class=\"titleClasses\">\n {{ option.title }}\n </h4>\n <h5 v-if=\"option.subtitle\" class=\"text-foreground-3 text-body-xs\">\n {{ option.subtitle }}\n </h5>\n </div>\n </div>\n <div\n class=\"h-5 w-5 rounded-full flex items-center justify-center border-[1.5px] border-outline-5\"\n >\n <div\n v-if=\"selected === option.value\"\n class=\"h-2.5 w-2.5 rounded-full bg-primary flex\"\n ></div>\n </div>\n </div>\n <div\n v-if=\"option.introduction\"\n class=\"text-body-2xs text-foreground pb-1 select-none text-left pr-20\"\n >\n {{ option.introduction }}\n </div>\n <slot :name=\"option.value\" />\n </div>\n </button>\n <div\n v-if=\"option.help\"\n class=\"sm:hidden text-xs flex space-x-0.5 mt-2 text-foreground\"\n >\n <InformationCircleIcon class=\"h-4 w-4\" />\n {{ option.help }}\n </div>\n </div>\n </div>\n <div v-if=\"!isStacked\" class=\"hidden sm:flex space-x-3 w-full\">\n <div v-for=\"option in options\" :key=\"option.value\" class=\"w-full\">\n <div\n v-if=\"option.help\"\n class=\"text-xs flex space-x-0.5 mt-2 text-foreground select-none\"\n >\n <InformationCircleIcon class=\"h-4 w-4\" />\n {{ option.help }}\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"Value extends string\">\nimport { InformationCircleIcon } from '@heroicons/vue/24/outline'\nimport { type ConcreteComponent, computed } from 'vue'\n\ntype OptionType = {\n value: Value\n title: string\n subtitle?: string\n introduction?: string\n icon?: ConcreteComponent\n help?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n options: OptionType[]\n disabled?: boolean\n isStacked?: boolean\n size?: 'sm' | 'base'\n }>(),\n {\n size: 'base'\n }\n)\n\nconst selected = defineModel<Value>()\n\nconst selectItem = (value: Value) => {\n selected.value = value\n}\n\nconst titleClasses = computed(() => {\n const classes = ['font-medium text-foreground']\n if (props.size === 'sm') {\n classes.push('text-body-sm')\n } else {\n classes.push('text-body')\n }\n return classes\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, watch } from 'vue'\nimport type { Ref, ToRefs } from 'vue'\nimport type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'\nimport { nanoid } from 'nanoid'\nimport { debounce, isArray, isBoolean, isString, isUndefined, noop } from 'lodash'\nimport type { LabelPosition } from './input'\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 customErrorMessage?: string\n hideErrorMessage?: boolean\n color?: InputColor\n labelPosition?: LabelPosition\n customHelpClass?: string\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: veeErrorMessage } = useField<V>(\n props.name,\n props.rules,\n {\n validateOnMount: unref(props.validateOnMount),\n validateOnValueUpdate: unref(props.validateOnValueUpdate),\n initialValue: unref(props.modelValue) || undefined\n }\n )\n\n const labelClasses = computed(() => {\n const classParts = [\n 'flex text-body-xs font-medium gap-1 items-center',\n unref(props.color) === 'foundation' ? 'text-foreground' : 'text-foreground-2',\n unref(props.labelPosition) !== 'left' ? 'pb-1' : null\n ]\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-md'\n ]\n\n return classParts.join(' ')\n })\n\n const coreClasses = computed(() => {\n const classParts = [\n 'block w-full text-foreground transition-all text-body-sm',\n coreInputClasses.value\n ]\n\n if (hasError.value) {\n classParts.push('!border-danger')\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(\n 'bg-foundation !border border-outline-2 hover:border-outline-5 focus-visible:border-outline-4 !ring-0 focus-visible:!outline-0'\n )\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\n const errorMessage = computed(() => {\n if (unref(props.customErrorMessage)) {\n return unref(props.customErrorMessage)\n }\n\n const base = veeErrorMessage.value\n if (!base || !unref(props.useLabelInErrors)) return base\n return base.replace('Value', title.value)\n })\n\n const hasError = computed(() => !!errorMessage.value)\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 customHelpTipClass = computed(() => unref(props.customHelpClass))\n const helpTipId = computed(() =>\n hasHelpTip.value ? `${unref(props.name)}-${internalHelpTipId.value}` : undefined\n )\n const helpTipClasses = computed((): string => {\n const classParts = ['text-body-2xs break-words']\n classParts.push(hasError.value ? 'text-danger' : 'text-foreground-2')\n if (customHelpTipClass.value) {\n classParts.push(customHelpTipClass.value)\n }\n return classParts.join(' ')\n })\n const shouldShowClear = computed(() => {\n if (!unref(props.showClear)) return false\n return (value.value?.length || 0) > 0\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 shouldShowClear,\n hasError\n }\n}\n\ntype FormInputChangeEvent = { event?: Event; value: string }\n\n/**\n * Attach returned on and bind using v-on and v-bind, and then you can use the returned `value`\n * ref to get the input's value while ensuring normal input events are debounced and only change/clear\n * events cause the value to propagate immediately\n *\n * Very useful for search inputs and other kind of auto-submitting inputs!\n */\nexport function useDebouncedTextInput(params?: {\n /**\n * For how long should basic input events be debounced.\n * Default: 1000 (ms)\n */\n debouncedBy?: number\n\n /**\n * Optionally pass in the model ref that should be used as the source of truth\n */\n model?: Ref<MaybeNullOrUndefined<string>>\n\n /**\n * Set to true if you're tracking changes on a basic HTML input element. This will change the events\n * being used (e.g. input instead of update:modelValue)\n *\n * Default: false\n */\n isBasicHtmlInput?: boolean\n\n /**\n * Set to false if you don't want the change event to be emitted on Enter key press.\n * Setting only works for basic html inputs currently!\n *\n * Default: Default behavior (true for input, false for textarea)\n */\n submitOnEnter?: boolean\n\n /**\n * Set to true if you want to see debug output for how events fire and are handled\n */\n debug?: boolean | ((...logArgs: unknown[]) => void)\n}) {\n const { debouncedBy = 1000, isBasicHtmlInput = false, submitOnEnter } = params || {}\n const log = params?.debug\n ? isBoolean(params.debug)\n ? console.debug\n : params.debug\n : noop\n\n const value = params?.model || ref('')\n const model = ref(value.value)\n\n const getValue = (val: string | InputEvent | Event | FormInputChangeEvent) => {\n if (isString(val)) return val\n if ('value' in val) return val.value\n\n const target = val.target as Nullable<HTMLInputElement | HTMLTextAreaElement>\n return target?.value || ''\n }\n\n const debouncedValueUpdate = debounce((val: string) => {\n value.value = val\n log('Value updated: ' + val)\n }, debouncedBy)\n\n const inputEventName = isBasicHtmlInput ? 'input' : 'update:modelValue'\n const on = {\n [inputEventName]: (val: string | InputEvent) => {\n const newVal = getValue(val)\n model.value = newVal\n debouncedValueUpdate(newVal)\n log(`Input event [${inputEventName}] triggered: ${newVal}`)\n },\n clear: () => {\n debouncedValueUpdate.cancel()\n model.value = ''\n value.value = ''\n log('Clear event')\n },\n change: (val: FormInputChangeEvent | Event) => {\n const newVal = getValue(val)\n debouncedValueUpdate.cancel()\n value.value = newVal\n model.value = newVal\n log('Change event: ' + newVal)\n },\n keydown: (e: KeyboardEvent) => {\n if (!isBasicHtmlInput) return\n if (isUndefined(submitOnEnter)) return\n\n const isEnter = e.key === 'Enter'\n if (!isEnter) return\n\n const isTextarea = e.target instanceof HTMLTextAreaElement\n\n if (isTextarea) {\n if (submitOnEnter) {\n log('Triggering submit on enter')\n e.preventDefault()\n e.stopPropagation()\n on.change(e)\n }\n } else {\n if (!submitOnEnter) {\n log('Preventing submit on enter')\n e.preventDefault()\n e.stopPropagation()\n }\n }\n }\n }\n const bind = computed(() => ({\n modelValue: model.value || ''\n }))\n\n watch(value, (newVal, oldVal) => {\n if (oldVal === newVal && !oldVal && !newVal) return\n if (model.value === value.value) return\n model.value = value.value\n })\n\n return {\n on,\n bind,\n value\n }\n}\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div :class=\"computedWrapperClasses\">\n <div\n :class=\"\n labelPosition === 'left'\n ? 'w-full md:w-6/12 flex flex-col justify-center'\n : 'w-full'\n \"\n >\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n <div v-if=\"!showRequired\" class=\"text-body-2xs font-normal\">(optional)</div>\n </label>\n <span\n v-if=\"labelPosition === 'left' && helpTipId\"\n :id=\"`${helpTipId}-left`\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </span>\n </div>\n <div\n class=\"relative\"\n :class=\"labelPosition === 'left' ? 'w-full md:w-6/12' : 'w-full'\"\n >\n <textarea\n :id=\"name\"\n ref=\"inputElement\"\n v-model=\"value\"\n :name=\"name\"\n :class=\"[\n coreClasses,\n iconClasses,\n sizeClasses,\n textareaClasses || '',\n 'min-h-[6rem] sm:min-h-[3rem] simple-scrollbar'\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 @keydown.stop\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 <p\n v-if=\"labelPosition === 'top' && helpTipId\"\n :id=\"`${helpTipId}-top`\"\n :class=\"['mt-1.5', helpTipClasses]\"\n >\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { 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 { LabelPosition } from '~~/src/composables/form/input'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport { useTextInputCore } from '~~/src/composables/form/textInput'\n\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', val: string): void\n (e: 'change', val: { event?: Event; value: string }): void\n (e: 'input', val: { event?: Event; value: string }): void\n (e: 'clear'): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n /**\n * Unique ID for the input (must be unique page-wide)\n */\n name: string\n showLabel?: boolean\n help?: string\n placeholder?: string\n label?: string\n disabled?: boolean\n rules?: RuleExpression<string>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n useLabelInErrors?: boolean\n autoFocus?: boolean\n modelValue?: string\n showClear?: boolean\n fullWidth?: boolean\n showRequired?: boolean\n showOptional?: boolean\n color?: InputColor\n textareaClasses?: string\n size?: InputSize\n labelPosition?: LabelPosition\n wrapperClasses?: string\n }>(),\n {\n useLabelInErrors: true,\n modelValue: '',\n color: 'page',\n labelPosition: 'top',\n wrapperClasses: ''\n }\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 shouldShowClear\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 (shouldShowClear.value && errorMessage.value) {\n classParts.push('pr-12')\n } else if (shouldShowClear.value || errorMessage.value) {\n classParts.push('pr-8')\n }\n\n return classParts.join(' ')\n})\n\nconst sizeClasses = computed((): string => {\n switch (props.size) {\n case 'sm':\n return 'text-2xs !leading-tight'\n case 'lg':\n return 'text-sm'\n case 'xl':\n return 'text-base'\n case 'base':\n default:\n return 'text-body-xs'\n }\n})\n\nconst computedWrapperClasses = computed(() => {\n const classes = ['flex', props.wrapperClasses]\n if (props.fullWidth) {\n classes.push('w-full')\n }\n\n if (props.labelPosition === 'top') {\n classes.push('flex-col')\n }\n if (props.labelPosition === 'left') {\n classes.push(\n 'w-full space-y-1 sm:space-y-0 sm:space-x-8 flex-col sm:flex-row items-start'\n )\n }\n return classes.join(' ')\n})\n\ndefineExpose({ focus })\n</script>\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div :class=\"computedWrapperClasses\">\n <div\n :class=\"\n labelPosition === 'left'\n ? 'w-full md:w-6/12 flex flex-col justify-center'\n : 'w-full'\n \"\n >\n <label :for=\"name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n <div v-if=\"showRequired\" class=\"text-danger text-body-xs opacity-80\">*</div>\n <div v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">(optional)</div>\n </label>\n <p\n v-if=\"labelPosition === 'left' && helpTipId && !hideHelpTip\"\n :id=\"helpTipId\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n\n <div\n class=\"group relative\"\n :class=\"labelPosition === 'left' ? 'w-full md:w-6/12' : 'w-full'\"\n >\n <div\n v-if=\"customIcon\"\n class=\"pointer-events-none absolute top-0 bottom-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 </div>\n <div\n v-if=\"loading\"\n class=\"absolute top-0 h-full right-0 flex items-center pr-2 text-foreground-3\"\n >\n <CommonLoadingIcon />\n </div>\n\n <div v-tippy=\"tooltipText\">\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 :readonly=\"readOnly\"\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 @keydown.stop\n />\n </div>\n <slot name=\"input-right\">\n <a\n v-if=\"rightIcon\"\n :title=\"rightIconTitle\"\n :class=\"[\n sizeClasses,\n readOnly\n ? 'w-full cursor-text border border-transparent group-hover:border-outline-5 rounded-md'\n : 'cursor-pointer'\n ]\"\n class=\"absolute top-0 right-0 hidden group-hover:flex items-center justify-end pr-1 text-foreground-2\"\n @click=\"onRightIconClick\"\n @keydown=\"onRightIconClick\"\n >\n <span class=\"text-body-xs sr-only\">{{ rightIconTitle }}</span>\n <Component\n :is=\"rightIcon\"\n class=\"h-6 w-6 text-foreground\"\n aria-hidden=\"true\"\n />\n </a>\n <a\n v-else-if=\"shouldShowClear\"\n title=\"Clear input\"\n class=\"absolute top-0 bottom-0 right-0 flex items-center pr-2 cursor-pointer\"\n @click=\"clear\"\n @keydown=\"clear\"\n >\n <span class=\"text-body-xs sr-only\">Clear input</span>\n <XMarkIcon class=\"h-5 w-5 text-foreground\" aria-hidden=\"true\" />\n </a>\n <div\n v-else-if=\"!showLabel && showRequired && !errorMessage\"\n class=\"pointer-events-none absolute top-0 bottom-0 mt-2 text-body right-0 flex items-center text-danger pr-2.5\"\n :class=\"[shouldShowClear ? 'pr-8' : 'pr-2']\"\n >\n *\n </div>\n </slot>\n </div>\n <p\n v-if=\"labelPosition === 'top' && helpTipId && !hideHelpTip\"\n :id=\"helpTipId\"\n :class=\"['mt-1.5', helpTipClasses]\"\n >\n {{ helpTip }}\n </p>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport type { RuleExpression } from 'vee-validate'\nimport { XMarkIcon } 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'\nimport type { InputColor } from '~~/src/composables/form/textInput'\nimport type { LabelPosition } from '~~/src/composables/form/input'\nimport { CommonLoadingIcon } from '~~/src/lib'\nimport { directive as vTippy } from 'vue-tippy'\n\ntype InputType = 'text' | 'email' | 'password' | 'url' | 'search' | 'number' | string\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\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 show the \"optional\" text\n */\n showOptional: {\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 * Whether to disable editing the component, making it read only\n */\n readOnly: {\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 inputClasses: {\n type: String,\n default: null\n },\n fullWidth: {\n type: Boolean,\n default: false\n },\n loading: {\n type: Boolean,\n default: false\n },\n hideErrorMessage: {\n type: Boolean,\n default: false\n },\n customErrorMessage: {\n type: String,\n default: null\n },\n wrapperClasses: {\n type: String,\n default: () => ''\n },\n color: {\n type: String as PropType<InputColor>,\n default: 'page'\n },\n labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n },\n rightIcon: {\n type: [Object, Function] as PropType<Optional<PropAnyComponent>>,\n default: undefined\n },\n rightIconTitle: {\n type: String,\n default: undefined\n },\n tooltipText: {\n type: String,\n default: undefined\n },\n customHelpClass: {\n type: String,\n default: undefined\n }\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', val: string): void\n (e: 'change', val: { event?: Event; value: string }): void\n (e: 'input', val: { event?: Event; value: string }): void\n (e: 'clear'): void\n (e: 'focus'): void\n (e: 'blur'): void\n (e: 'rightIconClick'): void\n}>()\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 shouldShowClear\n} = useTextInputCore({\n props: toRefs(props),\n emit,\n inputEl: inputElement\n})\n\nconst leadingIconClasses = computed(() => {\n const classParts: string[] = ['h-4 w-4']\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 iconClasses = computed((): string => {\n const classParts: string[] = []\n\n if (props.customIcon) {\n classParts.push('pl-8')\n }\n\n if (!slots['input-right']) {\n if (props.rightIcon || errorMessage.value || shouldShowClear.value) {\n classParts.push('pr-8')\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-body-sm'\n case 'lg':\n return 'h-10 text-[13px]'\n case 'xl':\n return 'h-14 text-sm'\n case 'base':\n default:\n return 'h-8 text-body-sm'\n }\n})\n\nconst computedWrapperClasses = computed(() => {\n const classes = ['flex', props.wrapperClasses]\n if (props.fullWidth) {\n classes.push('w-full')\n }\n\n if (props.labelPosition === 'top') {\n classes.push('flex-col')\n }\n if (props.labelPosition === 'left') {\n classes.push('w-full space-y-1 sm:space-y-0 sm:space-x-8 flex-col sm:flex-row')\n }\n return classes.join(' ')\n})\n\nconst onRightIconClick = () => {\n emit('rightIconClick')\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 = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\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\n/**\n * Used for placeholders inputs where the user can leave the field empty\n */\nexport const isEmailOrEmpty: GenericValidateFunction<string> = (val) =>\n (val || '').match(VALID_EMAIL) || !val\n ? true\n : '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 can't be longer than ${maxLength} characters`\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\nexport const isMultiItemSelected = <T>(val: T[] | unknown): true | string => {\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 :class=\"[\n 'relative w-full h-1 bg-blue-500/30 text-xs text-foreground-on-primary overflow-hidden rounded-xl',\n showBar ? 'opacity-100' : 'opacity-0'\n ]\"\n >\n <div class=\"swoosher relative top-0 bg-blue-500/50\"></div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport { useMounted } from '@vueuse/core'\nimport { computed } from 'vue'\n\nconst props = defineProps<{ loading: boolean; clientOnly?: boolean }>()\n\nconst mounted = useMounted()\nconst showBar = computed(() => (mounted.value || !props.clientOnly) && props.loading)\n</script>\n<style scoped>\n.swoosher {\n width: 100%;\n height: 100%;\n animation: swoosh 1s infinite linear;\n transform-origin: 0% 30%;\n}\n\n@keyframes swoosh {\n 0% {\n transform: translateX(0) scaleX(0);\n }\n\n 40% {\n transform: translateX(0) scaleX(0.4);\n }\n\n 100% {\n transform: translateX(100%) scaleX(0.5);\n }\n}\n</style>\n","<template>\n <!-- If multiple, use FormSelectMultiple instead -->\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 :class=\"{\n 'md:flex md:items-center md:space-x-2 md:justify-between': isLeftLabelPosition\n }\"\n >\n <div class=\"flex flex-col\" :class=\"{ 'pb-1': showLabel && !isLeftLabelPosition }\">\n <ListboxLabel\n :id=\"labelId\"\n class=\"flex text-body-xs text-foreground font-medium\"\n :class=\"[{ 'sr-only': !showLabel }, { 'items-center gap-1': showOptional }]\"\n :for=\"buttonId\"\n >\n {{ label }}\n <div v-if=\"showRequired\" class=\"text-danger text-xs opacity-80\">*</div>\n <div v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">\n (optional)\n </div>\n </ListboxLabel>\n <p\n v-if=\"helpTipId && isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"text-xs\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n <div v-tippy=\"tooltipText\">\n <div :class=\"buttonsWrapperClasses\">\n <!-- <div class=\"relative flex\"> -->\n <ListboxButton\n :id=\"buttonId\"\n ref=\"listboxButton\"\n v-slot=\"{ open }\"\n :class=\"buttonClasses\"\n >\n <div class=\"flex items-center justify-between w-full\">\n <div\n class=\"block truncate grow text-left text-xs sm:text-[13px]\"\n :class=\"[hasValueSelected ? 'text-foreground' : 'text-foreground-2']\"\n >\n <template\n v-if=\"\n !wrappedValue || (isArray(wrappedValue) && !wrappedValue.length)\n \"\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\n class=\"pointer-events-none shrink-0 ml-1 flex items-center space-x-2\"\n >\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=\"!showLabel && 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 <!-- Sync isOpen with dropdown open state -->\n <template v-if=\"(isOpen = open)\"></template>\n </ListboxButton>\n <!-- </div> -->\n <!-- Clear Button -->\n <button\n v-if=\"renderClearButton\"\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 top-0 bottom-0 left-0 flex items-center pl-2\"\n >\n <MagnifyingGlassIcon class=\"h-4 w-4 text-foreground-2\" />\n </div>\n <input\n ref=\"searchInput\"\n v-model=\"searchValue\"\n type=\"text\"\n class=\"py-1 pl-7 w-full bg-foundation placeholder:font-normal normal placeholder:text-foreground-2 text-[13px] focus-visible:[box-shadow:none] rounded-md hover:border-outline-5 focus-visible:border-outline-4\"\n :placeholder=\"searchPlaceholder\"\n @keydown.stop\n />\n </div>\n </label>\n <div class=\"overflow-auto simple-scrollbar max-h-60\">\n <div v-if=\"isAsyncSearchMode && isAsyncLoading\" class=\"px-1\">\n <CommonLoadingBar :loading=\"true\" />\n </div>\n <div v-else-if=\"isAsyncSearchMode && !currentItems.length\">\n <div class=\"text-foreground-2 text-center\">\n <slot name=\"nothing-found\">Nothing found</slot>\n </div>\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 as SingleItem)\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n <li\n v-tippy=\"\n disabledItemPredicate?.(item)\n ? disabledItemTooltip\n : undefined\n \"\n :class=\"\n listboxOptionClasses({\n active,\n disabled: disabledItemPredicate?.(item) || false\n })\n \"\n >\n <span\n class=\"block px-2 py-1.5 rounded-md\"\n :class=\"[\n selected ? 'bg-highlight-3' : '',\n !hideCheckmarks ? 'pr-8' : 'pr-2',\n !disabledItemPredicate?.(item) && !selected\n ? 'hover:bg-highlight-1'\n : ''\n ]\"\n >\n <slot\n name=\"option\"\n class=\"truncate\"\n :item=\"item\"\n :active=\"active\"\n :selected=\"selected\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n {{ simpleDisplayText(item) }}\n </slot>\n\n <span\n v-if=\"!hideCheckmarks && selected\"\n :class=\"[\n 'absolute top-0 bottom-0 right-0 text-foreground flex items-center pr-4'\n ]\"\n >\n <CheckIcon class=\"h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </span>\n </li>\n </ListboxOption>\n </template>\n </div>\n </ListboxOptions>\n </Teleport>\n </Transition>\n </div>\n </div>\n </Listbox>\n <p\n v-if=\"helpTipId && !isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"mt-2 text-xs\"\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>\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/20/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 { useElementBounding, useMounted, useIntersectionObserver } from '@vueuse/core'\nimport type { LabelPosition } from '~~/src/composables/form/input'\nimport { directive as vTippy } from 'vue-tippy'\n\ntype ButtonStyle = 'base' | 'simple' | 'tinted'\ntype ValueType = SingleItem | SingleItem[] | undefined\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\n\nconst isObjectLikeType = (v: unknown): v is Record<string, unknown> => isObjectLike(v)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: ValueType): void\n}>()\n\nconst props = defineProps({\n size: {\n type: String as PropType<Optional<InputSize>>,\n default: undefined\n },\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<\n Optional<RuleExpression<ValueType>>\n >,\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 /**\n * @deprecated Use size attribute instead\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 show the optional text\n */\n showOptional: {\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 labelId: {\n type: String,\n default: undefined\n },\n buttonId: {\n type: String,\n default: undefined\n },\n /**\n * Tooltip shown on disabled items\n */\n disabledItemTooltip: {\n required: false,\n type: String\n },\n labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n },\n tooltipText: {\n type: String,\n default: undefined\n }\n})\n\nconst { value, errorMessage: error } = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\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())\nconst isOpen = ref(false)\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 isLeftLabelPosition = computed(() => props.labelPosition === 'left')\n\nconst renderClearButton = computed(\n () => props.buttonStyle !== 'simple' && props.clearable && !props.disabled\n)\n\nconst sizeClasses = computed((): string => {\n if (!props.size) return ''\n\n switch (props.size) {\n case 'sm':\n return 'h-6 text-body-sm'\n case 'lg':\n return 'h-10 text-[13px]'\n case 'xl':\n return 'h-14 text-sm'\n case 'base':\n default:\n return 'h-8 text-body-sm'\n }\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')\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('border border-danger')\n }\n } else if (props.buttonStyle !== 'simple') {\n classParts.push('rounded-md border')\n if (isOpen.value) {\n classParts.push('border-outline-4')\n } else {\n classParts.push('border-outline-2 hover:border-outline-5 focus:outline-0')\n }\n }\n\n if (props.fixedHeight) {\n classParts.push('h-8')\n } else if (sizeClasses.value?.length) {\n classParts.push(sizeClasses.value)\n }\n\n if (isLeftLabelPosition.value) {\n classParts.push('md:basis-1/2')\n }\n\n return classParts.join(' ')\n})\n\nconst commonButtonClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.buttonStyle !== 'simple') {\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 focus:outline-outline-4 focus:outline-1',\n commonButtonClasses.value\n ]\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('p-2')\n\n if (!isDisabled.value) {\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-foundation 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 py-1 label label--light border border-outline-3 shadow-md 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-40')\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 { disabled } = params || {}\n\n const classParts = ['relative transition select-none py-1 px-2']\n\n if (disabled) {\n classParts.push('opacity-50 cursor-not-allowed')\n } else {\n classParts.push('text-foreground cursor-pointer')\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 void debouncedSearch()\n})\n\nonMounted(() => {\n if (isAsyncSearchMode.value && !props.items.length) {\n void 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 :label-id=\"labelId\"\n :button-id=\"buttonId\"\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<{\n (e: 'update:modelValue', v: ValueType): void\n}>()\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 labelId: {\n type: String\n },\n buttonId: {\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 :label-id=\"labelId\"\n :button-id=\"buttonId\"\n >\n <template #something-selected=\"{ value }\">\n <ul class=\"flex flex-wrap gap-1.5\">\n <li v-for=\"item in isArrayValue(value) ? value : [value]\" :key=\"item[by]\">\n <CommonBadge\n size=\"lg\"\n color-classes=\"border border-outline-2 bg-foundation-page\"\n dot-icon-color-classes=\"text-foreground\"\n rounded\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-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<{\n (e: 'update:modelValue', val: Array<SingleItem>): void\n}>()\n\nconst props = defineProps<{\n items: Array<SingleItem>\n label: string\n name: string\n help?: string\n modelValue?: SingleItem | SingleItem[] | undefined\n multiple?: boolean\n rules?: Array<any>\n by: string\n labelId?: string\n buttonId?: string\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>\n <div\n :key=\"forceUpdateKey\"\n :class=\"{\n 'md:flex md:items-center md:space-x-2 md:justify-between': isLeftLabelPosition\n }\"\n >\n <div class=\"flex flex-col\" :class=\"{ 'pb-1': showLabel && !isLeftLabelPosition }\">\n <label\n :id=\"labelId\"\n class=\"flex text-body-xs text-foreground font-medium pointer-events-none\"\n :class=\"[{ 'sr-only': !showLabel }, { 'items-center gap-1': showOptional }]\"\n :for=\"buttonId\"\n >\n {{ label }}\n <div v-if=\"showRequired\" class=\"text-danger text-xs opacity-80\">*</div>\n <div v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">\n (optional)\n </div>\n </label>\n <p\n v-if=\"helpTipId && isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"text-xs\"\n :class=\"helpTipClasses\"\n >\n {{ helpTip }}\n </p>\n </div>\n <div v-tippy=\"tooltipText\">\n <div :class=\"buttonsWrapperClasses\">\n <button\n :id=\"buttonId\"\n ref=\"listboxButton\"\n type=\"button\"\n :class=\"buttonClasses\"\n :aria-expanded=\"isOpen\"\n :aria-haspopup=\"true\"\n @click=\"toggleDropdown\"\n >\n <div class=\"flex items-center justify-between w-full\">\n <div\n class=\"block truncate grow text-left text-xs sm:text-[13px]\"\n :class=\"[hasValueSelected ? 'text-foreground' : 'text-foreground-2']\"\n >\n <template\n v-if=\"\n !wrappedValue || (isArray(wrappedValue) && !wrappedValue.length)\n \"\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\n class=\"pointer-events-none shrink-0 ml-1 flex items-center space-x-2\"\n >\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=\"!showLabel && showRequired\"\n class=\"text-4xl text-danger opacity-50 h-4 w-4 leading-6\"\n >\n *\n </div>\n <ChevronUpIcon\n v-if=\"isOpen\"\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 </button>\n\n <button\n v-if=\"renderClearButton\"\n :class=\"clearButtonClasses\"\n :disabled=\"disabled\"\n @click=\"clearValue()\"\n >\n <XMarkIcon class=\"w-3 h-3\" />\n </button>\n\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 <div\n v-if=\"isOpen\"\n ref=\"menuEl\"\n :class=\"listboxOptionsClasses\"\n :style=\"listboxOptionsStyle\"\n role=\"listbox\"\n :aria-labelledby=\"labelId\"\n @focus=\"searchInput?.focus()\"\n >\n <!-- Search input section -->\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 top-0 bottom-0 left-0 flex items-center pl-2\"\n >\n <MagnifyingGlassIcon class=\"h-4 w-4 text-foreground-2\" />\n </div>\n <input\n ref=\"searchInput\"\n v-model=\"searchValue\"\n type=\"text\"\n class=\"py-1 pl-7 w-full bg-foundation placeholder:font-normal normal placeholder:text-foreground-2 text-[13px] focus-visible:[box-shadow:none] rounded-md hover:border-outline-5 focus-visible:border-outline-4\"\n :placeholder=\"searchPlaceholder\"\n @keydown.stop\n />\n </div>\n </label>\n\n <div\n ref=\"optionsContainer\"\n class=\"overflow-auto simple-scrollbar max-h-60 xl:max-h-80 gap-1 flex flex-col\"\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 <div class=\"text-foreground-2 text-center\">\n <slot name=\"nothing-found\">Nothing found</slot>\n </div>\n </div>\n <template v-if=\"!isAsyncSearchMode || !isAsyncLoading\">\n <button\n v-for=\"item in finalItems\"\n :key=\"itemKey(item)\"\n v-tippy=\"\n disabledItemPredicate?.(item) ? disabledItemTooltip : undefined\n \"\n type=\"button\"\n role=\"option\"\n :aria-selected=\"isSelected(item)\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n :class=\"\n listboxOptionClasses({\n disabled: disabledItemPredicate?.(item) || false\n })\n \"\n @click=\"(e) => selectItem(item, e)\"\n >\n <div\n class=\"block w-full px-2 py-1.5 rounded-md text-left flex items-center gap-1\"\n :class=\"[\n !hideCheckmarks ? 'pr-8' : 'pr-2',\n !disabledItemPredicate?.(item) && !isSelected(item)\n ? 'hover:bg-highlight-1'\n : ''\n ]\"\n >\n <FormCheckbox\n :name=\"`select-${itemKey(item)}`\"\n :checked=\"isSelected(item)\"\n :disabled=\"disabledItemPredicate?.(item)\"\n :hide-label=\"true\"\n @change.stop\n />\n <slot\n name=\"option\"\n class=\"truncate\"\n :item=\"item\"\n :selected=\"isSelected(item)\"\n :disabled=\"disabledItemPredicate?.(item) || false\"\n >\n {{ simpleDisplayText(item) }}\n </slot>\n </div>\n </button>\n </template>\n </div>\n </div>\n </Teleport>\n </Transition>\n </div>\n </div>\n </div>\n <p\n v-if=\"helpTipId && !isLeftLabelPosition\"\n :id=\"helpTipId\"\n class=\"mt-2 text-xs\"\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>\nimport {\n ChevronDownIcon,\n ChevronUpIcon,\n MagnifyingGlassIcon,\n XMarkIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/20/solid'\nimport { debounce, isArray, isObjectLike } from 'lodash'\nimport type { CSSProperties, PropType, Ref } from 'vue'\nimport { computed, onMounted, ref, unref, watch, nextTick } 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 {\n useElementBounding,\n useMounted,\n useIntersectionObserver,\n onClickOutside\n} from '@vueuse/core'\nimport type { LabelPosition } from '~~/src/composables/form/input'\nimport { directive as vTippy } from 'vue-tippy'\nimport FormCheckbox from '~~/src/components/form/Checkbox.vue'\n\ntype ButtonStyle = 'base' | 'simple' | 'tinted'\ntype ValueType = SingleItem | SingleItem[] | undefined\ntype InputSize = 'sm' | 'base' | 'lg' | 'xl'\n\nconst isObjectLikeType = (v: unknown): v is Record<string, unknown> => isObjectLike(v)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', v: ValueType): void\n}>()\n\nconst props = defineProps({\n size: {\n type: String as PropType<Optional<InputSize>>,\n default: undefined\n },\n items: {\n type: Array as PropType<SingleItem[]>,\n default: () => []\n },\n modelValue: {\n type: [Array, Object, String, Number] 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<\n Optional<RuleExpression<ValueType>>\n >,\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 /**\n * @deprecated Use size attribute instead\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 show the optional text\n */\n showOptional: {\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 labelId: {\n type: String,\n default: undefined\n },\n buttonId: {\n type: String,\n default: undefined\n },\n /**\n * Tooltip shown on disabled items\n */\n disabledItemTooltip: {\n required: false,\n type: String\n },\n labelPosition: {\n type: String as PropType<LabelPosition>,\n default: 'top'\n },\n tooltipText: {\n type: String,\n default: undefined\n }\n})\n\nconst { value, errorMessage: error } = useField<ValueType>(props.name, props.rules, {\n validateOnMount: props.validateOnMount,\n validateOnValueUpdate: props.validateOnValueUpdate,\n initialValue: isArray(props.modelValue) ? props.modelValue : []\n})\n\nconst isMounted = useMounted()\n\nconst searchInput = ref(null as Nullable<HTMLInputElement>)\nconst menuEl = ref<HTMLDivElement | null>(null)\nconst listboxButton = ref<HTMLButtonElement | null>(null)\nconst searchValue = ref('')\nconst currentItems = ref([]) as Ref<SingleItem[]>\nconst isAsyncLoading = ref(false)\nconst forceUpdateKey = ref(1)\nconst internalHelpTipId = ref(nanoid())\nconst isOpen = ref(false)\n\nconst listboxButtonBounding = useElementBounding(listboxButton, {\n windowResize: true,\n windowScroll: true,\n immediate: true\n})\n\nuseIntersectionObserver(\n computed(() => menuEl.value),\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 isLeftLabelPosition = computed(() => props.labelPosition === 'left')\n\nconst renderClearButton = computed(\n () => props.buttonStyle !== 'simple' && props.clearable && !props.disabled\n)\n\nconst sizeClasses = computed((): string => {\n if (!props.size) return ''\n\n switch (props.size) {\n case 'sm':\n return 'h-6 text-body-sm'\n case 'lg':\n return 'h-10 text-[13px]'\n case 'xl':\n return 'h-14 text-sm'\n case 'base':\n default:\n return 'h-8 text-body-sm'\n }\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')\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('border border-danger')\n }\n } else if (props.buttonStyle !== 'simple') {\n classParts.push('rounded-md border')\n if (isOpen.value) {\n classParts.push('border-outline-4')\n } else {\n classParts.push('border-outline-2 hover:border-outline-5 focus:outline-0')\n }\n }\n\n if (props.fixedHeight) {\n classParts.push('h-8')\n } else if (sizeClasses.value?.length) {\n classParts.push(sizeClasses.value)\n }\n\n if (isLeftLabelPosition.value) {\n classParts.push('md:basis-1/2')\n }\n\n return classParts.join(' ')\n})\n\nconst commonButtonClasses = computed(() => {\n const classParts: string[] = []\n\n if (props.buttonStyle !== 'simple') {\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 focus:outline-outline-4 focus:outline-1',\n commonButtonClasses.value\n ]\n\n if (props.buttonStyle !== 'simple') {\n classParts.push('p-2')\n\n if (!isDisabled.value) {\n if (props.buttonStyle === 'tinted') {\n classParts.push('bg-foundation 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 return isArray(currentValue) ? currentValue : []\n },\n set: (newVal) => {\n if (!isArray(newVal)) {\n console.warn('Attempting to set non-array value in selector')\n return\n }\n\n if (props.fullyControlValue) {\n emit('update:modelValue', newVal)\n } else {\n value.value = newVal\n }\n\n forceUpdateKey.value += 1\n }\n})\n\nconst hasValueSelected = computed(() => {\n if (isArray(wrappedValue.value)) return wrappedValue.value.length !== 0\n else return !!wrappedValue.value\n})\n\nconst clearValue = () => {\n wrappedValue.value = []\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 py-1 label label--light border border-outline-3 shadow-md 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-40')\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: { disabled: boolean }) => {\n const { disabled } = params\n const classParts = ['relative transition select-none px-2']\n\n if (disabled) {\n classParts.push('opacity-50 cursor-not-allowed')\n } else {\n classParts.push('text-foreground cursor-pointer')\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 void debouncedSearch()\n})\n\nonMounted(() => {\n if (isAsyncSearchMode.value && !props.items.length) {\n void triggerSearch()\n }\n})\n\nconst toggleDropdown = () => {\n if (!isDisabled.value) {\n isOpen.value = !isOpen.value\n }\n}\n\nconst isSelected = (item: SingleItem) => {\n return wrappedValue.value.some((v) => itemKey(v) === itemKey(item))\n}\n\nconst optionsContainer = ref<HTMLDivElement | null>(null)\nconst scrollPosition = ref(0)\n\nconst selectItem = (item: SingleItem, event?: Event) => {\n if (props.disabledItemPredicate?.(item)) return\n event?.stopPropagation()\n\n scrollPosition.value = optionsContainer.value?.scrollTop || 0\n\n const currentValue = wrappedValue.value\n const itemExists = currentValue.some((v) => itemKey(v) === itemKey(item))\n\n wrappedValue.value = itemExists\n ? currentValue.filter((v) => itemKey(v) !== itemKey(item))\n : [...currentValue, item]\n\n void nextTick(() => {\n if (optionsContainer.value) {\n optionsContainer.value.scrollTop = scrollPosition.value\n }\n })\n}\n\nonClickOutside(\n menuEl,\n () => {\n if (isOpen.value) {\n isOpen.value = false\n }\n },\n {\n ignore: [listboxButton]\n }\n)\n\ndefineExpose({ triggerSearch })\n</script>\n","<template>\n <div class=\"flex items-center space-x-2\">\n <HeadlessSwitch\n :id=\"id || name\"\n v-model=\"enabled\"\n :class=\"switchClasses\"\n :name=\"name\"\n :disabled=\"disabled\"\n >\n <span :class=\"sliderClasses\"></span>\n </HeadlessSwitch>\n <label :for=\"id || name\" :class=\"labelClasses\">\n <span>{{ title }}</span>\n </label>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { Switch as HeadlessSwitch } from '@headlessui/vue'\nimport { computed } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n showLabel?: boolean\n name: string\n label?: string\n disabled?: boolean\n id?: string\n }>(),\n {\n showLabel: true\n }\n)\n\nconst enabled = defineModel<boolean>()\n\nconst title = computed(() => props.label || props.name)\n\nconst labelClasses = computed(() => {\n const classParts = ['block label-light']\n\n if (!props.showLabel) {\n classParts.push('sr-only')\n }\n\n return classParts.join(' ')\n})\n\nconst switchClasses = computed(() => {\n const classParts = [\n 'relative inline-flex flex-shrink-0 h-[18px] w-[30px] rounded-full',\n 'transition-colors ease-in-out duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary',\n 'cursor-pointer disabled:cursor-not-allowed disabled:opacity-40'\n ]\n\n if (enabled.value) {\n classParts.push('bg-primary')\n } else {\n classParts.push('bg-foreground-3')\n }\n\n return classParts.join(' ')\n})\n\nconst sliderClasses = computed(() => {\n const classParts = [\n 'pointer-events-none inline-block h-3 w-3 rounded-full mt-[3px] ml-[3px]',\n 'ring-0 transition ease-in-out duration-200 bg-foreground-on-primary'\n ]\n\n if (enabled.value) {\n classParts.push('translate-x-[12px]')\n } else {\n classParts.push('translate-x-0')\n }\n\n return classParts.join(' ')\n})\n</script>\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div\n class=\"relative group bg-foundation border border-outline-2 p-2 rounded-lg pr-20\"\n >\n <div\n v-if=\"isMultiline\"\n class=\"relative z-10 text-body-2xs select-all 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-body-2xs text-foreground font-mono select-all\"\n />\n <div class=\"absolute top-3 right-2 flex justify-end items-center\">\n <FormButton\n color=\"outline\"\n size=\"sm\"\n :icon-left=\"\n isIconButton\n ? copied\n ? ClipboardDocumentCheckIcon\n : ClipboardDocumentIcon\n : undefined\n \"\n :hide-text=\"isIconButton\"\n @click=\"handleCopy\"\n >\n {{ copied ? 'Copied' : 'Copy' }}\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 isIconButton?: boolean\n rows?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isMultiline: false\n})\n\nconst emit = defineEmits<{ (e: 'copy', val: string): void }>()\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","<template>\n <div class=\"flex flex-col items-center\">\n <div class=\"flex gap-2\">\n <div v-for=\"(_, index) in digitCount\" :key=\"index\" class=\"w-10\">\n <FormTextInput\n ref=\"inputRefs\"\n v-model=\"digits[index]\"\n class=\"text-center !text-[14px] py-6 !px-2 font-semibold\"\n color=\"foundation\"\n :name=\"`code-${index}`\"\n type=\"text\"\n inputmode=\"numeric\"\n :disabled=\"disabled\"\n :error=\"internalError\"\n :custom-error-message=\"internalError ? ' ' : undefined\"\n maxlength=\"1\"\n size=\"lg\"\n @input=\"onInput(index)\"\n @keydown=\"onKeyDown(index, $event)\"\n @paste=\"onPaste\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted, ref, watch } from 'vue'\nimport { FormTextInput } from '~~/src/lib'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n digitCount?: number\n disabled?: boolean\n error?: boolean\n clearErrorOnEdit?: boolean\n }>(),\n {\n digitCount: 6,\n clearErrorOnEdit: true\n }\n)\n\nconst emit = defineEmits(['update:modelValue', 'complete'])\n\nconst inputRefs = ref<Array<HTMLInputElement | null>>([])\nconst digits = ref<string[]>(new Array(props.digitCount).fill('') as string[])\nconst internalError = ref(props.error)\n\nconst onInput = (index: number) => {\n if (props.clearErrorOnEdit) {\n internalError.value = false\n }\n\n digits.value[index] = digits.value[index].replace(/[^0-9]/g, '')\n\n // Move to next input if available\n if (digits.value[index] && index < props.digitCount - 1) {\n inputRefs.value[index + 1]?.focus()\n }\n}\n\nconst onKeyDown = (index: number, event: KeyboardEvent) => {\n if (event.key === 'Backspace' && !digits.value[index] && index > 0) {\n if (props.clearErrorOnEdit) {\n internalError.value = false\n }\n // Move to previous input on backspace if current is empty\n digits.value[index - 1] = ''\n inputRefs.value[index - 1]?.focus()\n } else if (event.key === 'ArrowLeft' && index > 0) {\n // Move to previous input on left arrow\n inputRefs.value[index - 1]?.focus()\n } else if (event.key === 'ArrowRight' && index < props.digitCount - 1) {\n // Move to next input on right arrow\n inputRefs.value[index + 1]?.focus()\n }\n}\n\nconst onPaste = (event: ClipboardEvent) => {\n if (props.clearErrorOnEdit) {\n internalError.value = false\n }\n event.preventDefault()\n const pastedData = event.clipboardData?.getData('text')\n if (!pastedData) return\n\n const numbers = pastedData.replace(/[^0-9]/g, '').split('')\n\n digits.value = [\n ...numbers.slice(0, props.digitCount),\n ...(Array(Math.max(0, props.digitCount - numbers.length)).fill('') as string[])\n ]\n\n // Focus the next empty input or the last input\n const nextEmptyIndex = digits.value.findIndex((d) => !d)\n if (nextEmptyIndex !== -1) {\n inputRefs.value[nextEmptyIndex]?.focus()\n } else {\n inputRefs.value[props.digitCount - 1]?.focus()\n }\n}\n\n// Focus first input on mount\nonMounted(() => {\n if (inputRefs.value[0]) {\n inputRefs.value[0].focus()\n }\n})\n\n// Watch external error prop changes\nwatch(\n () => props.error,\n (newValue) => {\n internalError.value = newValue\n }\n)\n\n// Watch for external value changes\nwatch(\n () => props.modelValue,\n (newValue) => {\n if (newValue) {\n const newDigits = newValue.split('')\n digits.value = [\n ...newDigits,\n ...(Array(props.digitCount - newDigits.length).fill('') as string[])\n ]\n } else {\n digits.value = Array(props.digitCount).fill('') as string[]\n }\n },\n { immediate: true }\n)\n\n// Watch for completion\nwatch(\n digits,\n (newDigits) => {\n const value = newDigits.join('')\n emit('update:modelValue', value)\n\n // Emit complete when all digits are filled\n if (value.length === props.digitCount) {\n emit('complete', value)\n }\n },\n { deep: true }\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 ? '⌘' : '⌃',\n [ModifierKeys.AltOrOpt]: clientOs === OperatingSystem.Mac ? '⌥' : 'Alt',\n [ModifierKeys.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 { useMagicKeys, whenever } 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\nexport type LabelPosition = 'top' | 'left'\n\n/**\n * onKeyDown wrapper that also checks for modifier keys being pressed\n */\nexport function onKeyboardShortcut(\n modifiers: ModifierKeys[],\n key: string,\n callback: () => void\n) {\n const keys = useMagicKeys()\n\n const modifierKeys = modifiers.map((modifier) => {\n switch (modifier) {\n case ModifierKeys.CtrlOrCmd:\n return clientOs === OperatingSystem.Mac ? 'Meta' : 'Control'\n case ModifierKeys.AltOrOpt:\n return 'Alt'\n case ModifierKeys.Shift:\n return 'Shift'\n default:\n return ''\n }\n })\n\n const keyCombination = `${modifierKeys.join('+')}+${key}`\n\n whenever(keys[keyCombination], callback)\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-50\" open @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-400\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n class=\"fixed top-0 left-0 w-full h-full backdrop-blur-xs bg-black/60 dark:bg-neutral-900/60 transition-opacity\"\n />\n </TransitionChild>\n <div class=\"fixed top-0 left-0 z-10 h-screen !h-[100dvh] w-screen\">\n <div\n class=\"flex md:justify-center h-full w-full md:p-6\"\n :class=\"[\n fullscreen === 'none' || fullscreen === 'desktop'\n ? 'p-4 items-center'\n : 'items-end md:items-center'\n ]\"\n >\n <TransitionChild\n as=\"template\"\n enter=\"ease-out duration-5000\"\n :enter-from=\"`md:opacity-0 ${\n fullscreen === 'mobile' || fullscreen === 'all'\n ? 'translate-y-[100%]'\n : 'translate-y-4'\n } md:translate-y-4`\"\n enter-to=\"md:opacity-100 translate-y-0\"\n leave=\"ease-in duration-5000\"\n leave-from=\"md:opacity-100 translate-y-0\"\n :leave-to=\"`md:opacity-0 ${\n fullscreen === 'mobile' || fullscreen === 'all'\n ? 'translate-y-[100%]'\n : 'translate-y-4'\n } md:translate-y-4`\"\n @after-leave=\"$emit('fully-closed')\"\n >\n <DialogPanel\n :class=\"dialogPanelClasses\"\n dialog-panel-classes\n :as=\"isForm ? 'form' : 'div'\"\n @submit.prevent=\"onFormSubmit\"\n >\n <div\n v-if=\"hasTitle\"\n class=\"border-b border-outline-3\"\n :class=\"scrolledFromTop && 'relative z-20 shadow-lg'\"\n >\n <div\n class=\"flex items-center justify-start rounded-t-lg shrink-0 min-h-[2rem] sm:min-h-[3rem] px-6 py-4 truncate text-heading-sm\"\n >\n <div class=\"flex items-center pr-12\">\n <ChevronLeftIcon\n v-if=\"showBackButton\"\n class=\"w-5 h-5 -ml-1 mr-3\"\n @click=\"$emit('back')\"\n />\n <div class=\"w-full truncate\">\n {{ title }}\n <slot name=\"header\" />\n </div>\n </div>\n </div>\n </div>\n\n <!--\n Due to how forms work, if there's no other submit button, on form submission the first button\n will be clicked. This is a workaround to prevent the close button from being that first button.\n https://stackoverflow.com/a/4763911/3194577\n -->\n <button class=\"hidden\" type=\"button\" />\n\n <FormButton\n v-if=\"!hideCloser\"\n color=\"subtle\"\n size=\"sm\"\n class=\"absolute z-20 top-4 right-5 shrink-0 !w-6 !h-6 !p-0\"\n @click=\"open = false\"\n >\n <XMarkIcon class=\"h-6 w-6 text-foreground-2\" />\n </FormButton>\n <div ref=\"slotContainer\" :class=\"slotContainerClasses\" @scroll=\"onScroll\">\n <slot>Put your content here!</slot>\n </div>\n <div\n v-if=\"hasButtons\"\n class=\"relative z-50 flex justify-end px-6 pb-6 space-x-2 shrink-0 bg-foundation-page\"\n :class=\"{\n 'shadow-t pt-6': !scrolledToBottom,\n [buttonsWrapperClasses || '']: true\n }\"\n >\n <template v-if=\"buttons\">\n <FormButton\n v-for=\"(button, index) in buttons\"\n :key=\"button.id || index\"\n v-bind=\"button.props || {}\"\n :disabled=\"button.props?.disabled || button.disabled\"\n :submit=\"button.props?.submit || button.submit\"\n @click=\"($event) => button.onClick?.($event)\"\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, type LayoutDialogButton } from '~~/src/lib'\nimport { XMarkIcon, ChevronLeftIcon } from '@heroicons/vue/24/outline'\nimport { useResizeObserver, type ResizeObserverCallback } from '@vueuse/core'\nimport { computed, ref, useSlots, watch, onUnmounted, type SetupContext } from 'vue'\nimport { throttle } from 'lodash'\nimport { isClient } from '@vueuse/core'\n\ntype MaxWidthValue = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\ntype FullscreenValues = 'mobile' | 'desktop' | 'all' | 'none'\n\nconst emit = defineEmits<{\n (e: 'update:open', v: boolean): void\n (e: 'fully-closed'): void\n (e: 'back'): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n open: boolean\n maxWidth?: MaxWidthValue\n fullscreen?: FullscreenValues\n hideCloser?: boolean\n showBackButton?: boolean\n /**\n * Prevent modal from closing when the user clicks outside of the modal or presses Esc\n */\n preventCloseOnClickOutside?: boolean\n title?: string\n buttons?: Array<LayoutDialogButton>\n /**\n * Extra classes to apply to the button container.\n */\n buttonsWrapperClasses?: string\n /**\n * If set, the modal will be wrapped in a form element and the `onSubmit` callback will be invoked when the user submits the form\n */\n onSubmit?: (e: SubmitEvent) => void\n isTransparent?: boolean\n }>(),\n {\n fullscreen: 'mobile'\n }\n)\n\nconst slots: SetupContext['slots'] = useSlots()\n\nconst scrolledFromTop = ref(false)\nconst scrolledToBottom = ref(true)\nconst slotContainer = ref<HTMLElement | null>(null)\n\nuseResizeObserver(\n slotContainer,\n throttle<ResizeObserverCallback>(() => {\n // Triggering onScroll on size change too so that we don't get stuck with shadows\n // even tho the new content is not scrollable\n onScroll({ target: slotContainer.value })\n }, 60)\n)\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 'xs':\n return 0\n case 'sm':\n return 1\n case 'md':\n return 2\n case 'lg':\n return 3\n case 'xl':\n return 4\n default:\n return 10000\n }\n})\n\nconst widthClasses = computed(() => {\n const classParts: string[] = ['w-full', 'sm:w-full']\n\n if (!isFullscreenDesktop.value) {\n if (maxWidthWeight.value === 0) {\n classParts.push('md:max-w-sm')\n }\n if (maxWidthWeight.value >= 1) {\n classParts.push('md:max-w-lg')\n }\n if (maxWidthWeight.value >= 2) {\n classParts.push('md:max-w-2xl')\n }\n if (maxWidthWeight.value >= 3) {\n classParts.push('lg:max-w-3xl')\n }\n if (maxWidthWeight.value >= 4) {\n classParts.push('xl:max-w-6xl')\n } else {\n classParts.push('md:max-w-2xl')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst isFullscreenDesktop = computed(\n () => props.fullscreen === 'desktop' || props.fullscreen === 'all'\n)\n\nconst dialogPanelClasses = computed(() => {\n const classParts: string[] = [\n 'transform md:rounded-xl text-foreground overflow-hidden transition-all text-left flex flex-col md:h-auto'\n ]\n\n if (!props.isTransparent) {\n classParts.push('bg-foundation-page shadow-xl border border-outline-2')\n }\n\n if (isFullscreenDesktop.value) {\n classParts.push('md:h-full')\n } else {\n classParts.push('md:max-h-[90vh]')\n }\n\n if (props.fullscreen === 'mobile' || props.fullscreen === 'all') {\n classParts.push('max-md:h-[98vh] max-md:!h-[98dvh]')\n }\n\n if (props.fullscreen === 'none' || props.fullscreen === 'desktop') {\n classParts.push('rounded-lg max-h-[90vh]')\n } else {\n classParts.push('rounded-t-lg')\n }\n\n classParts.push(widthClasses.value)\n return classParts.join(' ')\n})\n\nconst slotContainerClasses = computed(() => {\n const classParts: string[] = ['flex-1 simple-scrollbar overflow-y-auto text-body-xs']\n\n if (!props.isTransparent) {\n if (hasTitle.value) {\n classParts.push('px-6 py-4')\n if (isFullscreenDesktop.value) {\n classParts.push('md:p-0')\n }\n } else if (!isFullscreenDesktop.value) {\n classParts.push('px-6 py-4')\n }\n }\n\n return classParts.join(' ')\n})\n\nconst onClose = () => {\n if (props.preventCloseOnClickOutside) return\n open.value = false\n}\n\nconst onFormSubmit = (e: SubmitEvent) => {\n props.onSubmit?.(e)\n}\n\nconst onScroll = throttle((e: { target: EventTarget | null }) => {\n if (!e.target) return\n\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\n// Toggle 'dialog-open' class on <html> to prevent scroll jumping and disable background scroll.\n// This maintains user scroll position when Headless UI dialogs are activated.\nwatch(open, (newValue) => {\n if (isClient) {\n const html = document.documentElement\n if (newValue) {\n html.classList.add('dialog-open')\n } else {\n html.classList.remove('dialog-open')\n }\n }\n})\n\n// Clean up when the component unmounts\nonUnmounted(() => {\n if (isClient) {\n document.documentElement.classList.remove('dialog-open')\n }\n})\n</script>\n\n<style>\nhtml.dialog-open {\n overflow: visible !important;\n}\nhtml.dialog-open body {\n overflow: hidden !important;\n}\n</style>\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 space-x-4 sm:space-x-8 py-2.5 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-heading-sm flex items-center space-x-1 sm:space-x-2 select-none\"\n :class=\"titleClasses\"\n >\n <div v-if=\"$slots.icon || icon\" class=\"h-4 w-4 empty:h-0 empty:w-0\">\n <slot v-if=\"$slots.icon\" name=\"icon\" />\n <Component :is=\"icon\" v-if=\"icon\" class=\"w-full h-full\" />\n </div>\n <span>{{ title }}</span>\n </div>\n <div>\n <ChevronDownIcon\n v-if=\"!button && !alwaysOpen\"\n class=\"w-4 h-4 transition-all duration-400\"\n :class=\"isExpanded && 'rotate-180'\"\n />\n <FormButton\n v-if=\"button\"\n :to=\"button.expandContent ? undefined : button.to\"\n :color=\"button.expandContent && isExpanded ? 'outline' : button.color\"\n :icon-right=\"\n button.expandContent && isExpanded ? undefined : button.iconRight\n \"\n size=\"sm\"\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-300 overflow-hidden\"\n :class=\"[\n allowOverflow && isExpanded ? '!overflow-visible' : '',\n isExpanded ? 'mb-2 mt-1' : '',\n !button && !alwaysOpen ? 'cursor-pointer hover:bg-foundation-page' : ''\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 { PropType, 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'\nimport type { FormButtonStyle } from '~~/src/helpers/form/button'\n\ntype TitleColor = 'default' | 'danger' | 'warning' | 'success' | 'secondary' | '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: FormButtonStyle\n iconRight?: PropAnyComponent | undefined\n onClick?: () => void\n }\n | undefined,\n alwaysOpen: Boolean,\n lazyLoad: {\n type: Boolean,\n default: false\n },\n icon: {\n type: [Function, Object] as PropType<PropAnyComponent>,\n default: undefined\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-page-2')\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 <HeadlessDisclosure 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 </HeadlessDisclosure>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n DisclosureButton,\n Disclosure as HeadlessDisclosure,\n DisclosurePanel\n} 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 = withDefaults(\n defineProps<{\n title: string\n /**\n * HeadlessUI icon component to use\n */\n icon?: PropAnyComponent\n color?: DisclosureColor\n }>(),\n {\n color: 'default'\n }\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'\nimport type { FormButton } from '~~/src/lib'\n\ntype FormButtonProps = InstanceType<typeof FormButton>['$props']\nimport type { PropAnyComponent } from '~~/src/helpers/common/components'\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 count?: number\n tag?: string\n icon?: PropAnyComponent\n disabled?: boolean\n disabledMessage?: 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\nexport type LayoutDialogButton = {\n text: string\n props?: Record<string, unknown> & FormButtonProps\n onClick?: (e: MouseEvent) => void\n disabled?: boolean\n disabledMessage?: string\n submit?: boolean\n /**\n * This should uniquely identify the button within the form. Even if you have different sets\n * of buttons rendered on different steps of a wizard, all of them should have unique IDs to\n * ensure proper form functionality.\n */\n id?: string\n}\n\nexport type LayoutTableColours = 'primary' | 'outline' | 'subtle' | 'danger'\n","<template>\n <button\n class=\"max-w-max transition flex justify-center items-center space-x-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.List\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=\"'List View'\"\n class=\"relative z-10 flex space-x-1 items-center p-1 rounded-l\"\n >\n <Bars3Icon class=\"h-5 w-5\" />\n </div>\n <div\n v-tippy=\"'Grid View'\"\n class=\"relative z-10 flex space-x-1 items-center p-1 rounded-r\"\n >\n <Squares2X2Icon 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<{\n (e: 'click', v: MouseEvent): void\n (e: 'update:modelValue', v: GridListToggleValue): void\n}>()\n\nconst props = defineProps<{\n modelValue?: GridListToggleValue\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 <HeadlessMenu v-slot=\"{ open: isMenuOpen }\" as=\"div\" class=\"relative inline-block\">\n <div>\n <MenuButton :id=\"menuId\" 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 ref=\"menuButtonWrapper\" :class=\"isMenuOpen ? 'pointer-events-none' : ''\">\n <slot :toggle=\"toggle\" :open=\"processOpen(isMenuOpen)\" />\n </div>\n </div>\n <Teleport to=\"body\" :disabled=\"!mountMenuOnBody\">\n <MenuItems\n v-if=\"isMenuOpen\"\n ref=\"menuItems\"\n :class=\"[\n 'mt-1 w-44 origin-top-right divide-y divide-outline-3 rounded-md bg-foundation shadow-lg border border-outline-2 z-50',\n menuDirection === HorizontalDirection.Left ? 'right-0' : '',\n mountMenuOnBody ? 'fixed' : 'absolute',\n size === 'lg' ? 'w-52' : 'w-44'\n ]\"\n :style=\"menuItemsStyles\"\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-4 w-4\" />\n <slot name=\"item\" :item=\"item\">{{ item.title }}</slot>\n </button>\n </span>\n </MenuItem>\n </div>\n </MenuItems>\n </Teleport>\n </HeadlessMenu>\n</template>\n\n<script setup lang=\"ts\">\nimport { directive as vTippy } from 'vue-tippy'\nimport { Menu as HeadlessMenu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'\nimport type { Nullable } from '@speckle/shared'\nimport { computed, ref, watch, onMounted } from 'vue'\nimport {\n HorizontalDirection,\n useResponsiveHorizontalDirectionCalculation\n} from '~~/src/composables/common/window'\nimport type { LayoutMenuItem } from '~~/src/helpers/layout/components'\nimport { useElementBounding, useEventListener } from '@vueuse/core'\n\nconst emit = defineEmits<{\n (e: 'update:open', val: boolean): void\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (e: 'chosen', val: { event: MouseEvent; item: LayoutMenuItem<any> }): void\n}>()\n\nconst props = defineProps<{\n open?: boolean\n /**\n * 2D array so that items can be grouped with dividers between them\n */\n items: LayoutMenuItem[][]\n size?: 'base' | 'lg'\n menuId?: string\n menuPosition?: HorizontalDirection\n mountMenuOnBody?: boolean\n}>()\n\nconst menuItems = ref(null as Nullable<{ el: HTMLDivElement }>)\nconst menuButton = ref(null as Nullable<{ el: HTMLButtonElement }>)\nconst menuButtonWrapper = ref(null as Nullable<HTMLElement>)\nconst isOpenInternally = ref(false)\nconst isMounted = ref(false)\n\nconst finalOpen = computed({\n get: () => props.open || false,\n set: (newVal) => emit('update:open', newVal)\n})\n\nconst menuButtonBounding = useElementBounding(menuButtonWrapper, {\n windowResize: true,\n windowScroll: true,\n immediate: true\n})\n\nconst menuItemsStyles = computed(() => {\n if (!props.mountMenuOnBody) return {}\n\n if (!menuButtonBounding.width.value) return {}\n let offsetPosition = menuButtonBounding.left.value\n\n if (props.menuPosition === HorizontalDirection.Left) {\n const menuWidth = props.size === 'lg' ? 175 : 143\n offsetPosition = menuButtonBounding.left.value - menuWidth\n }\n\n return {\n position: 'fixed',\n top: `${menuButtonBounding.top.value + menuButtonBounding.height.value}px`,\n left: `${offsetPosition}px`,\n zIndex: 50\n }\n})\n\nconst { direction: calculatedDirection } = useResponsiveHorizontalDirectionCalculation({\n el: computed(() => menuItems.value?.el || null),\n defaultDirection: HorizontalDirection.Left,\n stopUpdatesBelowWidth: 300\n})\n\nconst menuDirection = computed(() => {\n return props.menuPosition || calculatedDirection.value\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 space-x-2 w-full items-center rounded-md px-2 py-1 text-body-xs'\n ]\n\n if (active && !color) {\n classParts.push('bg-primary-muted text-foreground')\n } else if (disabled) {\n classParts.push('opacity-40')\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 = () => {\n menuButton.value?.el.click()\n if (props.mountMenuOnBody) {\n menuButtonBounding.update()\n }\n}\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\nonMounted(() => {\n isMounted.value = true\n})\n\nuseEventListener(window, 'resize', () => {\n menuButtonBounding.update()\n})\n\nuseEventListener(window, 'scroll', () => {\n menuButtonBounding.update()\n})\n</script>\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nexport default trimmedEndIndex;\n","import trimmedEndIndex from './_trimmedEndIndex.js';\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nexport default baseTrim;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseTrim from './_baseTrim.js';\nimport isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nexport default toNumber;\n","import root from './_root.js';\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\nexport default now;\n","import isObject from './isObject.js';\nimport now from './now.js';\nimport toNumber from './toNumber.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n clearTimeout(timerId);\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\nexport default debounce;\n","import debounce from './debounce.js';\nimport isObject from './isObject.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\nexport default throttle;\n","<template>\n <div class=\"relative z-10 flex flex-col !mt-0\">\n <!-- Left Arrow Button -->\n <div\n class=\"absolute left-[-2px] top-[-2px] z-20 pr-8 bg-gradient-to-r from-foundation-page to-transparent\"\n >\n <button\n v-if=\"showLeftArrow\"\n class=\"bg-foundation p-1 rounded-full border border-outline-4 shadow\"\n @click=\"scrollLeft\"\n >\n <ArrowLongLeftIcon class=\"h-4 w-4\" />\n </button>\n </div>\n <div class=\"absolute left-0 z-10 w-full h-[1px] mt-px bg-outline-3 top-8\"></div>\n <div\n ref=\"scrollContainer\"\n class=\"relative overflow-x-auto hide-scrollbar w-full\"\n @scroll=\"handleScroll\"\n >\n <div\n :style=\"borderStyle\"\n class=\"h-[2px] absolute bottom-0 z-20 transition-[left,width] duration-300\"\n :class=\"isInitialSetup ? 'bg-transparent' : 'bg-primary'\"\n ></div>\n\n <div ref=\"buttonContainer\" class=\"flex w-full space-x-4\">\n <button\n v-for=\"item in items\"\n :key=\"item.id\"\n :data-tab-id=\"item.id\"\n :class=\"[\n buttonClass(item),\n { '!border-primary': isActiveItem(item) && isInitialSetup }\n ]\"\n class=\"tab-button\"\n :disabled=\"item.disabled\"\n @click=\"setActiveItem(item)\"\n >\n <div class=\"flex space-x-2 items-center\">\n <component\n :is=\"item.icon\"\n v-if=\"item.icon\"\n class=\"shrink-0 h-4 w-4 stroke-[2px]\"\n />\n\n <div class=\"min-w-6\">\n <span\n v-if=\"item.disabled && item.disabledMessage\"\n v-tippy=\"item.disabledMessage\"\n >\n {{ item.title }}\n </span>\n <span v-else>{{ item.title }}</span>\n </div>\n <div\n v-if=\"item.count\"\n class=\"rounded-full px-2 text-body-3xs transition-all min-w-6\"\n :class=\"\n activeItem?.id === item.id\n ? 'text-primary bg-info-lighter dark:text-foreground'\n : 'text-foreground-2 bg-foundation-2'\n \"\n >\n <span>{{ item.count }}</span>\n </div>\n <CommonBadge v-if=\"item.tag\">\n {{ item.tag }}\n </CommonBadge>\n </div>\n </button>\n </div>\n </div>\n\n <!-- Right Arrow Button -->\n <div\n class=\"absolute right-[-2px] top-[-2px] z-20 pl-8 bg-gradient-to-l from-foundation-page to-transparent\"\n >\n <button\n v-if=\"showRightArrow\"\n class=\"bg-foundation p-1 rounded-full border border-outline-3 shadow\"\n @click=\"scrollRight\"\n >\n <ArrowLongRightIcon class=\"h-4 w-4\" />\n </button>\n </div>\n <div class=\"pt-4\">\n <slot :active-item=\"activeItem\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, onMounted, watch, onBeforeUnmount } from 'vue'\nimport type { CSSProperties } from 'vue'\nimport type { LayoutPageTabItem } from '~~/src/helpers/layout/components'\nimport { isClient } from '@vueuse/core'\nimport { ArrowLongRightIcon, ArrowLongLeftIcon } from '@heroicons/vue/24/outline'\nimport type { Nullable } from '@speckle/shared'\nimport { throttle } from '#lodash'\nimport { useElementSize } from '@vueuse/core'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\n\nconst props = defineProps<{\n items: LayoutPageTabItem[]\n}>()\n\nconst activeItem = defineModel<LayoutPageTabItem>('activeItem', { required: true })\n\nconst buttonContainer = ref(null as Nullable<HTMLDivElement>)\nconst scrollContainer = ref<HTMLElement | null>(null)\nconst showLeftArrow = ref(false)\nconst showRightArrow = ref(false)\nconst isInitialSetup = ref(true)\n\nconst { width } = useElementSize(buttonContainer)\n\nconst buttonClass = computed(() => {\n return (item: LayoutPageTabItem) => {\n const isActive = activeItem.value?.id === item.id\n const baseClasses = [\n 'relative',\n 'z-10',\n 'flex',\n 'items-center',\n 'disabled:opacity-60 disabled:hover:border-transparent disabled:cursor-not-allowed disabled:hover:bg-transparent',\n 'text-body-xs',\n 'hover:sm:border-outline-2',\n 'pb-2',\n 'border-b-[2px]',\n 'border-transparent',\n 'max-w-max',\n 'last:mr-6',\n 'whitespace-nowrap'\n ]\n\n if (isActive) baseClasses.push('text-primary', 'hover:text-primary')\n else baseClasses.push('text-foreground')\n\n return baseClasses\n }\n})\n\nconst activeItemRef = computed(() => {\n const id = activeItem.value?.id\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 HTMLElement[]\n return btns.find((b) => b.dataset['tabId'] === id) || null\n})\n\nconst borderStyle = computed<CSSProperties>(() => {\n // Using width in calculation to force dependency\n return width.value\n ? {\n left: `${activeItemRef.value?.offsetLeft || 0}px`,\n width: `${activeItemRef.value?.clientWidth || 0}px`\n }\n : {\n left: '0px',\n width: '0px'\n }\n})\n\nconst setActiveItem = (item: LayoutPageTabItem) => {\n activeItem.value = item\n isInitialSetup.value = false\n}\n\nconst isActiveItem = (item: LayoutPageTabItem) => {\n return activeItem.value?.id === item.id\n}\n\nconst checkArrowsVisibility = () => {\n const container = scrollContainer.value\n if (!container) return\n\n const scrollWidth = container.scrollWidth\n const clientWidth = container.clientWidth\n const scrollLeft = container.scrollLeft\n const buffer = 1\n\n showLeftArrow.value = scrollLeft > buffer\n showRightArrow.value = scrollLeft < scrollWidth - clientWidth - buffer\n}\n\nconst scrollLeft = () => {\n scrollContainer.value?.scrollBy({ left: -100, behavior: 'smooth' }) // Adjust the scroll amount as needed\n checkArrowsVisibility()\n}\n\nconst scrollRight = () => {\n scrollContainer.value?.scrollBy({ left: 100, behavior: 'smooth' }) // Adjust the scroll amount as needed\n checkArrowsVisibility()\n}\n\nconst handleScroll = throttle(() => {\n checkArrowsVisibility()\n}, 250)\n\nconst ensureActiveItemVisible = () => {\n const activeButton = activeItemRef.value\n if (activeButton && scrollContainer.value) {\n activeButton.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'center'\n })\n }\n}\n\nonMounted(() => {\n if (isClient) {\n if (props.items.length && !activeItem.value) {\n setActiveItem(props.items[0])\n }\n checkArrowsVisibility()\n ensureActiveItemVisible()\n }\n})\n\nwatch(\n () => [props.items, activeItem.value] as const,\n ([newItems]) => {\n if (Array.isArray(newItems) && newItems.length && !activeItem.value) {\n setActiveItem(newItems[0])\n }\n checkArrowsVisibility()\n }\n)\n\nonBeforeUnmount(() => {\n handleScroll.cancel()\n})\n</script>\n<style>\n/* Hide scrollbar for Chrome, Safari and Opera */\n.hide-scrollbar::-webkit-scrollbar {\n display: none;\n}\n\n/* Hide scrollbar for IE, Edge and Firefox */\n.hide-scrollbar {\n -ms-overflow-style: none; /* IE and Edge */\n scrollbar-width: none; /* Firefox */\n}\n</style>\n","<template>\n <div class=\"flex space-y-8 lg:space-y-0 lg:space-x-8 flex-col lg:flex-row\">\n <div class=\"lg:w-2/12\">\n <div class=\"flex w-full flex-col space-y-1\">\n <button\n v-for=\"item in items\"\n :key=\"item.id\"\n :data-tab-id=\"item.id\"\n :class=\"[buttonClass(item)]\"\n :disabled=\"item.disabled\"\n @click=\"setActiveItem(item)\"\n >\n <div\n v-tippy=\"\n item.disabled && item.disabledMessage ? item.disabledMessage : undefined\n \"\n class=\"absolute top-0 right-0 left-0 bottom-0\"\n ></div>\n <div class=\"flex space-x-2 items-center px-2\">\n <component\n :is=\"item.icon\"\n v-if=\"item.icon\"\n class=\"shrink-0 h-4 w-4 stroke-[2px]\"\n ></component>\n <span class=\"min-w-6\">{{ item.title }}</span>\n <div\n v-if=\"item.count\"\n class=\"rounded-full px-2 text-body-3xs transition-all min-w-6\"\n :class=\"\n activeItem?.id === item.id\n ? 'text-primary bg-info-lighter dark:text-foreground'\n : 'text-foreground-2 bg-foundation-2'\n \"\n >\n <span>{{ item.count }}</span>\n </div>\n <div\n v-if=\"item.tag\"\n class=\"text-body-3xs font-medium py-0.5 px-1.5 text-foreground-2 bg-foundation-2 uppercase text-outline-4 rounded\"\n >\n {{ item.tag }}\n </div>\n </div>\n </button>\n </div>\n </div>\n\n <div class=\"lg:w-10/12\">\n <slot :active-item=\"activeItem\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onMounted, watch } from 'vue'\nimport type { LayoutPageTabItem } from '~~/src/helpers/layout/components'\nimport { isClient } from '@vueuse/core'\n\nconst props = defineProps<{\n items: LayoutPageTabItem[]\n}>()\n\nconst activeItem = defineModel<LayoutPageTabItem>('activeItem', { required: true })\n\nconst buttonClass = computed(() => {\n return (item: LayoutPageTabItem) => {\n const isActive = activeItem.value?.id === item.id\n const baseClasses = [\n 'relative',\n 'flex items-center space-x-1.5',\n 'hover:bg-highlight-2',\n 'disabled:opacity-60 disabled:hover:border-transparent disabled:cursor-not-allowed disabled:hover:bg-transparent rounded-md',\n 'text-body-xs font-medium',\n 'py-1'\n ]\n\n if (isActive) baseClasses.push('bg-primary-muted')\n else baseClasses.push('border-transparent text-foreground')\n\n return baseClasses\n }\n})\n\nconst setActiveItem = (item: LayoutPageTabItem) => {\n activeItem.value = item\n}\n\nonMounted(() => {\n if (isClient) {\n if (props.items.length && !activeItem.value) {\n setActiveItem(props.items[0])\n }\n }\n})\n\nwatch(\n () => [props.items, activeItem.value],\n ([newItems]) => {\n if (Array.isArray(newItems) && newItems.length && !activeItem.value) {\n setActiveItem(newItems[0])\n }\n }\n)\n</script>\n","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\n<template>\n <div class=\"text-foreground\">\n <div\n class=\"w-full text-sm overflow-x-auto overflow-y-visible simple-scrollbar border border-outline-3 rounded-lg\"\n >\n <div :class=\"headerRowClasses\" :style=\"{ paddingRight: paddingRightStyle }\">\n <div\n v-for=\"(column, colIndex) in columns\"\n :key=\"column.id\"\n :class=\"getHeaderClasses(column.id, colIndex)\"\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-if=\"loading || !items\"\n class=\"flex items-center justify-center py-3\"\n tabindex=\"0\"\n >\n <CommonLoadingIcon />\n </div>\n <template v-else-if=\"items?.length\">\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\n v-if=\"buttons\"\n class=\"absolute right-1.5 space-x-1 flex items-center p-0 h-full\"\n >\n <div v-for=\"button in buttons\" :key=\"button.label\">\n <FormButton\n v-tippy=\"button.tooltip\"\n :icon-left=\"button.icon\"\n size=\"sm\"\n color=\"outline\"\n hide-text\n :class=\"button.class\"\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 </template>\n <div\n v-else\n tabindex=\"0\"\n :style=\"{ paddingRight: paddingRightStyle }\"\n :class=\"rowsWrapperClasses\"\n >\n <div :class=\"getClasses(undefined, 0)\" tabindex=\"0\">\n <slot name=\"empty\">\n <div class=\"w-full text-center label-light text-foreground-2 italic\">\n {{ emptyMessage }}\n </div>\n </slot>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\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 { CommonLoadingIcon, FormButton } from '~~/src/lib'\nimport { directive as vTippy } from 'vue-tippy'\n\nexport type TableColumn<I> = {\n id: I\n header: string\n classes: string\n}\n\nexport type RowButton<T = unknown> = {\n icon: PropAnyComponent\n label: string\n action: (item: T) => unknown\n class?: string\n tooltip?: string\n}\n\nconst props = withDefaults(\n defineProps<{\n items: T[] | undefined | null\n buttons?: RowButton<T>[]\n columns: TableColumn<C>[]\n overflowCells?: boolean\n onRowClick?: (item: T) => void\n rowItemsAlign?: 'center' | 'stretch'\n emptyMessage?: string\n loading?: boolean\n }>(),\n { rowItemsAlign: 'center', emptyMessage: 'No data found' }\n)\n\nconst buttonCount = computed(() => {\n return (props.buttons || []).length\n})\nconst paddingRightStyle = computed(() => {\n let padding = 16\n if (buttonCount.value > 0) {\n padding = 48 + (buttonCount.value - 1) * 42\n }\n return `${padding}px`\n})\n\nconst rowsWrapperClasses = computed(() => {\n const classParts = [\n 'relative grid grid-cols-12 items-center space-x-6 px-4 py-0.5 min-w-[750px] text-body-xs'\n ]\n\n if (props.onRowClick && props.items?.length) {\n classParts.push('cursor-pointer hover:bg-highlight-1')\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 = (\n column: C | undefined,\n colIndex: number,\n options?: Partial<{\n noPadding: boolean\n }>\n): string => {\n const columnClasses = column\n ? props.columns.find((c) => c.id === column)?.classes\n : ''\n const classParts = [columnClasses || '']\n\n if (!options?.noPadding) {\n if (colIndex === 0) {\n classParts.push('px-1')\n } else {\n classParts.push('lg:p-0 px-1')\n }\n }\n\n return classParts.join(' ')\n}\n\nconst getClasses = (\n column: C | undefined,\n colIndex: number,\n options?: Partial<{\n noPadding: boolean\n }>\n): string => {\n const classParts = [getHeaderClasses(column, colIndex, options)]\n\n if (colIndex === 0) {\n classParts.push(`bg-transparent py-2 ${column ? 'pr-5' : 'col-span-full'}`)\n } else {\n classParts.push(`my-2`)\n }\n\n return classParts.join(' ')\n}\n\nconst handleRowClick = (item: T) => {\n props.onRowClick?.(item)\n}\n\nconst headerRowClasses = computed(() => [\n 'z-10 grid grid-cols-12 items-center',\n 'w-full min-w-[750px] space-x-6',\n 'px-4 py-3',\n 'bg-foundation-2 rounded-t-lg',\n 'font-medium text-body-2xs text-foreground-2',\n 'border-b border-outline-3'\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<{\n (e: 'infinite', $state: InfiniteLoaderState): void\n}>()\n\ndefineProps<{\n /**\n * v3-infinite-loading props, see docs or type definitions\n */\n settings?: {\n target?: string\n distance?: number\n top?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n identifier?: any\n firstload?: boolean\n }\n /**\n * Whether to allow retry and show a retry button when loading fails\n */\n allowRetry?: 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 -top-1 -left-1 -right-1 -bottom-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<{ (e: 'submit', val: SubmitEvent): void }>()\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-1 hover:ring-1')\n }\n if (props.panelClasses) {\n classParts.push(props.panelClasses)\n }\n\n return classParts.join(' ')\n})\n</script>\n","<template>\n <!-- If promo content is defined, scroll the menu items. If not, scroll the whole aside -->\n <aside\n class=\"flex flex-col justify-between h-full w-full\"\n :class=\"$slots.promo ? '' : 'overflow-y-auto overflow-x-hidden simple-scrollbar'\"\n >\n <div\n class=\"flex flex-col h-full w-full\"\n :class=\"$slots.promo ? 'overflow-y-auto overflow-x-hidden simple-scrollbar' : ''\"\n >\n <slot></slot>\n </div>\n <div v-if=\"$slots.promo\" class=\"shrink-0 pt-2\">\n <slot name=\"promo\"></slot>\n </div>\n </aside>\n</template>\n","<template>\n <nav class=\"flex flex-col space-y-4\">\n <slot></slot>\n </nav>\n</template>\n","<template>\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M8 3V13M3 8H13\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </svg>\n</template>\n","<template>\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.66748 3.66687H3.00081C2.64719 3.66687 2.30805 3.80735 2.058 4.05739C1.80796 4.30744 1.66748 4.64658 1.66748 5.0002V11.0002C1.66748 11.3538 1.80796 11.693 2.058 11.943C2.30805 12.1931 2.64719 12.3335 3.00081 12.3335H9.00081C9.35443 12.3335 9.69357 12.1931 9.94362 11.943C10.1937 11.693 10.3341 11.3538 10.3341 11.0002V10.3335\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M12.59 3.39007C12.8526 3.12751 13.0001 2.77139 13.0001 2.40007C13.0001 2.02875 12.8526 1.67264 12.59 1.41007C12.3274 1.14751 11.9713 1 11.6 1C11.2287 1 10.8726 1.14751 10.61 1.41007L5 7.00007V9.00007H7L12.59 3.39007Z\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M9.66748 2.33313L11.6675 4.33313\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n</template>\n","<template>\n <svg\n width=\"16\"\n height=\"32\"\n viewBox=\"0 0 16 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7.64645 17.7498C7.84171 17.9451 8.15829 17.9451 8.35355 17.7498L11.1464 14.9569C11.4614 14.642 11.2383 14.1034 10.7929 14.1034H5.20711C4.76165 14.1034 4.53857 14.642 4.85355 14.9569L7.64645 17.7498Z\"\n fill=\"currentColor\"\n />\n </svg>\n</template>\n","<template>\n <div class=\"flex flex-col group\">\n <div\n v-if=\"title\"\n class=\"h-8 flex items-center justify-between select-none rounded-md\"\n :class=\"[collapsible && !noHover && 'hover:bg-highlight-1']\"\n >\n <component\n :is=\"collapsible ? 'button' : 'div'\"\n class=\"flex items-center w-full\"\n :class=\"[\n collapsible ? 'group rounded-md gap-x-1' : 'space-x-1 p-1 text-foreground-2',\n collapsible && !noHover ? 'py-0.5 px-2' : 'pl-2'\n ]\"\n @click=\"collapsible ? (isCollapsed = !isCollapsed) : undefined\"\n >\n <ArrowFilled\n v-if=\"collapsible\"\n :class=\"[isCollapsed ? '-rotate-90' : '', noHover ? '-ml-1' : '']\"\n class=\"text-foreground-2 shrink-0\"\n />\n <div\n v-if=\"$slots['title-icon']\"\n class=\"flex items-center justify-center\"\n :class=\"[collapsible ? 'ml-1 mr-2' : '']\"\n >\n <slot name=\"title-icon\"></slot>\n </div>\n <div class=\"flex flex-1 items-center truncate justify-between\">\n <h6\n class=\"truncate text-body-2xs pr-2\"\n :class=\"[nested ? 'text-foreground' : 'font-semibold text-foreground-2']\"\n >\n {{ title }}\n </h6>\n <CommonBadge v-if=\"tag\" rounded>\n {{ tag }}\n </CommonBadge>\n </div>\n </component>\n <button\n v-if=\"iconClick\"\n v-tippy=\"iconText ? iconText : undefined\"\n class=\"hidden group-hover:flex p-1 shrink-0 hover:bg-primary-muted rounded text-foreground-2\"\n :class=\"noHover ? '' : 'mr-2'\"\n @click=\"iconClick\"\n >\n <Edit v-if=\"icon === 'edit'\" class=\"h-4 w-4\" />\n <ChevronRightIcon v-else-if=\"icon === 'view'\" class=\"h-4 w-4\" />\n <Plus v-else class=\"h-4 w-4\" />\n </button>\n </div>\n\n <div v-show=\"!isCollapsed\" class=\"flex flex-col\">\n <slot></slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Plus from '~~/src/components/global/icon/Plus.vue'\nimport Edit from '~~/src/components/global/icon/Edit.vue'\nimport ArrowFilled from '~~/src/components/global/icon/ArrowFilled.vue'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\nimport { ChevronRightIcon } from '@heroicons/vue/24/outline'\n\ndefineProps<{\n tag?: string\n title?: string\n collapsible?: boolean\n collapsed?: boolean\n icon?: 'add' | 'edit' | 'view'\n iconText?: string\n iconClick?: () => void\n noHover?: boolean\n nested?: boolean\n}>()\n\nconst isCollapsed = defineModel<boolean>('collapsed')\n</script>\n","<template>\n <div\n v-if=\"!hasChildren\"\n v-tippy=\"tooltipText\"\n :to=\"to\"\n class=\"group/item flex items-center justify-between space-x-2 shrink-0 text-body-xs text-foreground select-none rounded-md w-full py-1\"\n :class=\"[\n !disabled && 'cursor-pointer hover:bg-highlight-1',\n disabled && 'cursor-not-allowed',\n active && 'bg-highlight-3 hover:!bg-highlight-3',\n $slots.icon ? 'pl-1 pr-2' : 'pr-2 pl-7',\n extraPadding && '!pl-14'\n ]\"\n >\n <div\n class=\"flex items-center space-x-2 truncate\"\n :class=\"[disabled && 'opacity-60']\"\n >\n <div v-if=\"$slots.icon\" class=\"h-6 w-6 flex items-center justify-center\">\n <slot name=\"icon\" />\n </div>\n <span class=\"truncate\">\n {{ label }}\n </span>\n <ArrowUpRightIcon\n v-if=\"external\"\n class=\"h-2.5 w-2.5 !stroke-[3px] -ml-1 -mt-1.5 opacity-0 group-hover/item:opacity-100 shrink-0\"\n />\n </div>\n <CommonBadge\n v-if=\"tag\"\n rounded\n :color-classes=\"\n colorClasses ?? (disabled ? 'text-foreground-2 bg-primary-muted' : undefined)\n \"\n >\n {{ tag }}\n </CommonBadge>\n </div>\n <div v-else class=\"flex flex-col\">\n <button\n v-tippy=\"tooltipText\"\n class=\"flex space-x-1.5 items-center w-full rounded-md p-0.5\"\n :class=\"[\n !disabled && 'cursor-pointer text-foreground-2 hover:text-foreground',\n disabled && 'opacity-60'\n ]\"\n @click=\"toggleOpen\"\n >\n <ArrowFilled class=\"h-1 w-2 shrink-0\" :class=\"[isOpen ? '' : '-rotate-90']\" />\n\n <h6 class=\"text-heading-sm flex items-center space-x-1.5\">\n {{ label }}\n </h6>\n </button>\n <div v-show=\"isOpen\" class=\"pl-4\">\n <slot></slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, useSlots, type SetupContext } from 'vue'\nimport ArrowFilled from '~~/src/components/global/icon/ArrowFilled.vue'\nimport { ArrowUpRightIcon } from '@heroicons/vue/24/outline'\nimport CommonBadge from '~~/src/components/common/Badge.vue'\n\nconst props = defineProps<{\n label: string\n to?: string\n tag?: string\n external?: boolean\n disabled?: boolean\n active?: boolean\n tooltipText?: string\n extraPadding?: boolean\n colorClasses?: string\n}>()\n\nconst isOpen = ref(true)\n\nconst slots: SetupContext['slots'] = useSlots()\n\nconst hasChildren = !!slots.default\n\nconst toggleOpen = () => {\n if (!props.disabled) {\n isOpen.value = !isOpen.value\n }\n}\n</script>\n","<template>\n <div :class=\"containerClasses\">\n <div :class=\"subcontainerClasses\">\n <div v-if=\"!hideIcon\">\n <Component :is=\"icon\" :class=\"iconClasses\" aria-hidden=\"true\" />\n </div>\n <div class=\"flex-1\">\n <h3 v-if=\"hasTitle\" :class=\"titleClasses\">\n <slot name=\"title\">Title</slot>\n </h3>\n <div v-if=\"hasDescription\" :class=\"descriptionClasses\">\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>\n <div class=\"flex gap-x-2\">\n <FormButton\n v-for=\"(action, i) in actions || []\"\n :key=\"i\"\n color=\"outline\"\n size=\"sm\"\n :to=\"action.url\"\n :external=\"action.externalUrl || false\"\n :disabled=\"action.disabled || false\"\n @click=\"handleActionClick(action)\"\n >\n {{ action.title }}\n </FormButton>\n </div>\n <div\n v-if=\"withDismiss\"\n class=\"flex\"\n :class=\"[hasDescription ? 'items-start' : 'items-center']\"\n >\n <FormButton type=\"button\" color=\"subtle\" size=\"sm\" @click=\"$emit('dismiss')\">\n Dismiss\n </FormButton>\n </div>\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n CheckCircleIcon,\n XCircleIcon,\n InformationCircleIcon,\n ExclamationCircleIcon\n} from '@heroicons/vue/24/outline'\nimport { noop } from 'lodash'\nimport { computed, useSlots, type SetupContext } from 'vue'\nimport FormButton from '~~/src/components/form/Button.vue'\nimport type {\n PropAnyComponent,\n AlertAction,\n AlertColor\n} from '~~/src/helpers/common/components'\n\ntype Size = 'default' | 'xs' | '2xs'\n\ndefineEmits<{ (e: 'dismiss'): void }>()\n\nconst props = withDefaults(\n defineProps<{\n color?: AlertColor\n withDismiss?: boolean\n actions?: Array<AlertAction>\n customIcon?: PropAnyComponent\n hideIcon?: boolean\n size?: Size\n }>(),\n {\n color: 'success',\n size: 'default'\n }\n)\n\nconst slots: SetupContext['slots'] = useSlots()\nconst hasDescription = computed(() => !!slots['description'])\nconst hasTitle = computed(() => !!slots['title'])\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 return CheckCircleIcon\n default:\n return InformationCircleIcon\n }\n})\n\nconst containerClasses = computed(() => {\n const classParts: string[] = ['rounded-lg text-foreground border border-outline-2']\n\n switch (props.size) {\n case '2xs':\n case 'xs':\n classParts.push('p-2')\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-lightest')\n break\n case 'info':\n classParts.push('bg-info-lightest')\n break\n case 'danger':\n classParts.push('bg-danger-lightest')\n break\n case 'warning':\n classParts.push('bg-warning-lightest')\n break\n case 'neutral':\n classParts.push('bg-foundation')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst subcontainerClasses = computed(() => {\n const classParts: string[] = ['flex items-center w-full']\n\n switch (props.size) {\n case '2xs':\n case 'xs':\n classParts.push('gap-x-1.5')\n break\n case 'default':\n default:\n classParts.push('gap-x-3')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case '2xs':\n classParts.push('h-4 w-4')\n break\n case 'xs':\n classParts.push('h-5 w-5')\n break\n case 'default':\n default:\n classParts.push('h-6 w-6')\n break\n }\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 dark:text-primary')\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 case 'neutral':\n classParts.push('text-foreground-2')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst titleClasses = computed(() => {\n const classParts: string[] = ['font-medium']\n\n switch (props.size) {\n case '2xs':\n classParts.push('text-body-2xs')\n break\n case 'default':\n default:\n classParts.push('text-body-xs')\n break\n }\n\n return classParts.join(' ')\n})\n\nconst descriptionClasses = computed(() => {\n const classParts: string[] = []\n\n switch (props.size) {\n case '2xs':\n classParts.push('text-body-2xs pt-0.5')\n break\n case 'default':\n default:\n classParts.push('text-body-xs')\n break\n }\n\n return classParts.join(' ')\n})\n\nfunction handleActionClick(action: AlertAction) {\n if (action.onClick) {\n action.onClick()\n } else {\n noop()\n }\n}\n</script>\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { type MaybeAsync, buildManualPromise } 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\nexport { buildManualPromise }\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\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}\n\nenum ComboboxStates {\n Open,\n Closed\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","<!-- eslint-disable vuejs-accessibility/no-static-element-interactions -->\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-else-if=\"showRequired\"\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 v-else-if=\"showOptional\" class=\"text-body-2xs font-normal\">(optional)</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 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 top-0 bottom-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\n v-if=\"helpTipId && !hideHelpTip\"\n :id=\"helpTipId\"\n class=\"mt-2\"\n :class=\"helpTipClasses\"\n >\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<{\n (e: 'update:modelValue', val: Tag[]): void\n (e: 'change', val: { event?: Event; value: Tag[] }): void\n (e: 'clear'): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n name: string\n help?: string\n label?: string\n showLabel?: boolean\n rules?: RuleExpression<Tag[]>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n autoFocus?: boolean\n showClear?: boolean\n showRequired?: boolean\n showOptional?: boolean\n color?: InputColor\n wrapperClasses?: string\n size?: InputSize\n placeholder?: string\n disabled?: boolean\n useLabelInErrors?: boolean\n getAutocompleteItems?: (query: string) => MaybeAsync<Tag[]>\n modelValue?: Tag[]\n }>(),\n {\n size: 'base',\n color: 'page',\n useLabelInErrors: true\n }\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 border-outline-3')\n if (isInputFocused.value) {\n classParts.push('ring-1 ring-outline-3')\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 = async () => {\n isAutocompleteLoading.value = true\n await 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 void 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 void 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 =\n | '2xs'\n | 'xs'\n | 'sm'\n | 'base'\n | 'lg'\n | 'xl'\n | 'xxl'\n | '3xl'\n | '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 '2xs':\n return 'h-4'\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-24'\n case '3xl':\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 '2xs':\n return 'w-4'\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-24'\n case '3xl':\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 '2xs':\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-2xl'\n case '3xl':\n return 'text-3xl'\n case 'editable':\n return 'h1'\n case 'base':\n default:\n return 'text-body-2xs'\n }\n })\n\n const iconClasses = computed(() => {\n const size = props.size?.value\n switch (size) {\n case '2xs':\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 uppercase transition',\n rounded ? 'rounded-full' : 'rounded-md',\n sizeClasses,\n bgClasses,\n borderClasses,\n hoverClasses,\n activeClasses\n ]\"\n >\n <slot>\n <div\n v-if=\"user?.avatar\"\n v-tippy=\"!hideTooltip ? props.user?.name : undefined\"\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 v-tippy=\"!hideTooltip ? props.user?.name : undefined\"\n :class=\"textClasses\"\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 = withDefaults(\n defineProps<{\n user?: MaybeNullOrUndefined<AvatarUser>\n size?: UserAvatarSize\n hoverEffect?: boolean\n active?: boolean\n noBorder?: boolean\n noBg?: boolean\n hideTooltip?: boolean\n rounded?: boolean\n lightStyle?: boolean\n }>(),\n {\n size: 'base',\n hoverEffect: false,\n user: null,\n rounded: true,\n lightStyle: false\n }\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 if (props.lightStyle) return 'border border-outline-2'\n return 'border-2 border-foundation'\n})\n\nconst bgClasses = computed(() => {\n if (props.noBg) return ''\n if (props.lightStyle) return 'bg-foundation-2'\n return 'bg-info-darker'\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\nconst textClasses = computed(() => {\n if (props.lightStyle) return 'text-foreground-3'\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 visibleUsers\"\n :key=\"user.id || i\"\n :user=\"user\"\n :size=\"size\"\n :hide-tooltip=\"hideTooltips\"\n />\n </div>\n <UserAvatar\n v-if=\"totalHiddenCount\"\n :size=\"size\"\n class=\"select-none\"\n :class=\"{ 'cursor-pointer': !!onHiddenCountClick }\"\n @click=\"onHiddenCountClick && onHiddenCountClick()\"\n >\n +{{ totalHiddenCount }}\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 = withDefaults(\n defineProps<{\n users: AvatarUserWithId[]\n overlap?: boolean\n size?: UserAvatarSize\n maxCount?: number\n hideTooltips?: boolean\n maxAvatars?: number\n onHiddenCountClick?: () => void\n }>(),\n {\n users: () => [],\n overlap: true,\n size: 'base',\n maxCount: undefined,\n hideTooltips: false,\n maxAvatars: undefined,\n onHiddenCountClick: undefined\n }\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 visibleUsers = computed(() => {\n const result = props.users\n const limit = Math.min(props.maxCount ?? Infinity, props.maxAvatars ?? Infinity)\n return result.slice(0, limit)\n})\n\nconst maxAvatarsHiddenCount = computed(() => {\n if (!props.maxAvatars) return 0\n return Math.max(props.users.length - props.maxAvatars, 0)\n})\n\nconst totalHiddenCount = computed(\n () =>\n hiddenItemCount.value + maxCountHiddenItemCount.value + maxAvatarsHiddenCount.value\n)\n</script>\n","<template>\n <svg\n class=\"spinner\"\n :class=\"iconClasses\"\n width=\"32px\"\n height=\"40px\"\n viewBox=\"0 0 66 66\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle\n class=\"path\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"6\"\n stroke-linecap=\"round\"\n cx=\"33\"\n cy=\"33\"\n r=\"30\"\n ></circle>\n </svg>\n</template>\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ntype Size = 'base' | 'sm' | 'lg'\n\nconst props = withDefaults(defineProps<{ loading?: boolean; size?: Size }>(), {\n size: 'base',\n loading: true\n})\n\nconst iconClasses = computed(() => {\n const classParts: string[] = ['']\n classParts.push(props.loading ? 'opacity-100' : 'opacity-0')\n\n switch (props.size) {\n case 'base':\n classParts.push('h-5 w-5')\n break\n case 'sm':\n classParts.push('h-4 w-4')\n break\n case 'lg':\n classParts.push('h-8 w-8')\n break\n }\n\n return classParts.join(' ')\n})\n</script>\n\n<style scoped>\n@keyframes rotator {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(270deg);\n }\n}\n\n@keyframes dash {\n 0% {\n stroke-dashoffset: 187;\n }\n 50% {\n stroke-dashoffset: 46.75;\n transform: rotate(135deg);\n }\n 100% {\n stroke-dashoffset: 187;\n transform: rotate(450deg);\n }\n}\n\n.spinner {\n animation: rotator 1.4s linear infinite;\n}\n\n.path {\n stroke-dasharray: 187;\n stroke-dashoffset: 0;\n transform-origin: center;\n animation: dash 1.4s ease-in-out infinite;\n}\n</style>\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 :rounded=\"rounded\"\n @cancel=\"editMode = false\"\n @save=\"onSave\"\n />\n <div v-else class=\"relative group\">\n <img\n v-if=\"!modelAsUser.avatar && defaultImg\"\n :src=\"defaultImg\"\n :alt=\"modelAsUser.name\"\n :class=\"sizeClasses\"\n />\n <UserAvatar\n v-else\n hide-tooltip\n :user=\"modelAsUser\"\n :size=\"size\"\n :light-style=\"lightStyle\"\n :rounded=\"rounded\"\n />\n <div\n class=\"opacity-0 transition-all absolute group-hover:opacity-100 top-0 right-0 left-0 bottom-0 flex items-end justify-center bottom-4\"\n >\n <FormButton\n size=\"sm\"\n :disabled=\"disabled\"\n color=\"outline\"\n @click=\"editMode = true\"\n >\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, toRefs } 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'\nimport { useAvatarSizeClasses } from '~~/src/composables/user/avatar'\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<{\n (e: 'save', newUrl: ModelType): void\n (e: 'update:modelValue', value: ModelType): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: ModelType\n /**\n * Placeholder name that will be used to generate and show initials if no avatar is present\n */\n placeholder: string\n /**\n * Name of the field. Used for validation & form submits\n */\n name: string\n rules?: RuleExpression<ModelType>\n validateOnMount?: boolean\n validateOnValueUpdate?: boolean\n disabled?: boolean\n size?: UserAvatarSize\n defaultImg?: string\n rounded?: boolean\n lightStyle?: boolean\n }>(),\n {\n rounded: true,\n lightStyle: false\n }\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})\nconst { sizeClasses } = useAvatarSizeClasses({ props: toRefs(props) })\n\nconst editMode = defineModel<boolean>('editMode')\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\">\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<{\n (e: 'files-selected', v: { files: UploadableFileItem[] }): void\n}>()\n\nconst props = withDefaults(\n defineProps<{\n /**\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept\n */\n accept?: string\n /**\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/multiple\n */\n multiple?: boolean\n /**\n * Max file size in bytes\n */\n sizeLimit?: number\n /**\n * Max file count if 'multiple' is set\n */\n countLimit?: number\n disabled?: boolean\n }>(),\n {\n sizeLimit: 1024 * 1024 * 100 // 100mb\n }\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","import type { Optional } from '@speckle/shared'\nimport type { Directive } from 'vue'\n\nconst keyboardClickableKeypressHandler = (e: KeyboardEvent) => {\n if (e.code !== 'Enter') return\n ;(e.target as Optional<HTMLElement>)?.click()\n}\n\n/**\n * Makes it possible to navigate to and click on the element using the keyboard\n */\nexport const vKeyboardClickable: Directive<HTMLElement> = {\n created(el) {\n el.setAttribute('tabindex', '0')\n el.addEventListener('keypress', keyboardClickableKeypressHandler)\n },\n unmounted(el) {\n el.removeEventListener('keypress', keyboardClickableKeypressHandler)\n }\n}\n","<template>\n <div class=\"relative w-full bg-outline-3 rounded h-1.5 overflow-hidden\">\n <div\n class=\"aboslute left-0 top-0 rounded h-1.5\"\n :class=\"colorClass\"\n :style=\"{ width: `${percentage <= 100 ? percentage : 100}%` }\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n currentValue: number\n maxValue: number\n}>()\n\nconst percentage = computed(() => (props.currentValue / props.maxValue) * 100)\nconst colorClass = computed(() => {\n if (percentage.value >= 100) {\n return 'bg-danger'\n }\n if (percentage.value >= 80) {\n return 'bg-warning'\n }\n\n return 'bg-success'\n})\n</script>\n"],"names":["emit","__emit","props","__props","NuxtLink","resolveDynamicComponent","RouterLink","linkComponent","computed","isObjectLike","buttonType","isDisabled","finalLeftIcon","CommonLoadingIcon","bgAndBorderClasses","classParts","colorsBgBorder","sizeClasses","paddingClasses","hasIconLeft","hasIconRight","hideText","generalClasses","baseClasses","additionalClasses","buttonClasses","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","_sfc_render","_ctx","_cache","_openBlock","_createElementBlock","_createElementVNode","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","checkboxClasses","onChange","newModelValue","newCoreValue","shouldBeChecked","isCoreChecked","radioValue","selected","_useModel","selectItem","titleClasses","useTextInputCore","inputEl","options","veeErrorMessage","unref","coreInputClasses","coreClasses","hasError","color","internalHelpTipId","base","hideHelpTip","helpTip","hasHelpTip","customHelpTipClass","helpTipId","helpTipClasses","shouldShowClear","focus","clear","isArray","useDebouncedTextInput","debouncedBy","isBasicHtmlInput","submitOnEnter","log","isBoolean","noop","model","getValue","val","isString","target","debouncedValueUpdate","debounce","inputEventName","on","isUndefined","bind","watch","oldVal","inputElement","computedWrapperClasses","__expose","slots","useSlots","leadingIconClasses","onRightIconClick","VALID_HTTP_URL","VALID_EMAIL","isEmail","isEmailOrEmpty","isOneOrMultipleEmails","i","isRequired","isSameAs","otherFieldName","otherFieldDisplayName","meta","isStringOfLength","minLength","maxLength","isNullOrUndefined","stringContains","match","message","isUrl","isItemSelected","isMultiItemSelected","useWrappingContainerHiddenCount","skipCalculation","elementToWatchForChanges","itemContainer","trackResize","trackMutations","hiddenItemCount","recalculate","avatarElements","visibleCount","totalCount","firstElOffsetTop","avatarEl","offsetTop","useResizeObserver","useMutationObserver","useFormSelectChildInternals","dynamicVisibility","selectedValue","currentValue","isArrayValue","v","mounted","useMounted","showBar","isObjectLikeType","error","isMounted","searchInput","menuEl","listboxButton","searchValue","currentItems","isAsyncLoading","forceUpdateKey","isOpen","listboxButtonBounding","useElementBounding","useIntersectionObserver","isIntersecting","isLeftLabelPosition","renderClearButton","buttonsWrapperClasses","commonButtonClasses","clearButtonClasses","hasValueSelected","hasSearch","isAsyncSearchMode","wrappedValue","finalValue","currentVal","itemKey","clearValue","finalItems","searchVal","listboxOptionsClasses","listboxOptionsStyle","style","top","left","width","height","simpleDisplayText","triggerSearch","debouncedSearch","listboxOptionClasses","disabled","newItems","hiddenSelectedItemCount","isMultiItemArrayValue","firstItem","searchFilterPredicate","search","deselectItem","item","toggleDropdown","isSelected","optionsContainer","scrollPosition","event","itemExists","nextTick","onClickOutside","enabled","switchClasses","sliderClasses","copy","useClipboard","copied","handleCopy","selectAllText","textElement","selection","range","inputRefs","digits","internalError","onInput","index","onKeyDown","onPaste","pastedData","numbers","nextEmptyIndex","d","newValue","newDigits","ModifierKeys","clientOs","getClientOperatingSystem","ModifierKeyTitles","OperatingSystem","getKeyboardShortcutTitle","keys","isModifierKey","k","onKeyboardShortcut","modifiers","key","callback","useMagicKeys","keyCombination","modifier","whenever","useFormCheckboxModel","isChecked","scrolledFromTop","scrolledToBottom","slotContainer","throttle","onScroll","isForm","hasButtons","hasTitle","open","maxWidthWeight","widthClasses","isFullscreenDesktop","dialogPanelClasses","slotContainerClasses","onClose","onFormSubmit","scrollTop","offsetHeight","scrollHeight","isClient","html","onUnmounted","content","contentHeight","isExpanded","backgroundClass","toggleExpansion","panelClasses","GridListToggleValue","ThrottleOrDebounce","ThrottleOrDebounce2","HorizontalDirection","HorizontalDirection2","useWindowResizeHandler","handler","throttleOrDebounce","finalHandler","useOnBeforeWindowUnload","useResponsiveHorizontalDirectionCalculation","el","defaultDirection","direction","stopUpdatesBelowWidth","element","recalculateDirection","rect","showOnLeftSide","showOnRightSide","menuItems","menuButton","menuButtonWrapper","isOpenInternally","finalOpen","menuButtonBounding","menuItemsStyles","offsetPosition","menuWidth","calculatedDirection","menuDirection","buildButtonClassses","active","chooseItem","toggle","processOpen","shouldBeOpen","useEventListener","freeGlobal","freeGlobal$1","freeSelf","root","root$1","Symbol","Symbol$2","objectProto","hasOwnProperty","nativeObjectToString","symToStringTag","getRawTag","isOwn","tag","unmasked","result","objectToString","nullTag","undefinedTag","baseGetTag","symbolTag","isSymbol","reWhitespace","trimmedEndIndex","string","reTrimStart","baseTrim","isObject","type","NAN","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","toNumber","other","isBinary","now","now$1","FUNC_ERROR_TEXT","nativeMax","nativeMin","func","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","args","thisArg","leadingEdge","timerExpired","remainingWait","timeSinceLastCall","timeSinceLastInvoke","timeWaiting","shouldInvoke","trailingEdge","cancel","flush","debounced","isInvoking","activeItem","buttonContainer","scrollContainer","showLeftArrow","showRightArrow","isInitialSetup","useElementSize","buttonClass","isActive","activeItemRef","id","parent","b","borderStyle","setActiveItem","isActiveItem","checkArrowsVisibility","container","scrollWidth","clientWidth","scrollLeft","buffer","scrollRight","handleScroll","ensureActiveItemVisible","activeButton","buttonCount","paddingRightStyle","padding","rowsWrapperClasses","getHeaderClasses","column","colIndex","c","getClasses","handleRowClick","headerRowClasses","wrapper","initializeLoader","int","secondarySlotPaddingClasses","defaultSlotPaddingClasses","$slots","isCollapsed","hasChildren","toggleOpen","hasDescription","icon","InformationCircleIcon","ExclamationCircleIcon","XCircleIcon","CheckCircleIcon","containerClasses","subcontainerClasses","handleActionClick","writableAsyncComputed","get","initialState","readOptions","set","asyncRead","debugging","logSettings","getTrace","logger","finalGet","res","finalSet","readValue","computedAsync","getter","provides","getCurrentInstance","ctxKey","s","state","inject","isInputEvent","isInputFocused","useFocus","ctxManager","autocompleteItems","isAutocompleteLoading","isAutocompleteOpen","query","selectedItems","uniq","t","inputWrapperClasses","removeTag","idx","newSelected","onQueryEscape","onQueryBackspace","newTags","onQueryArrowUp","onQueryArrowDown","resolveAutocompleteItems","debouncedResolve","debouncedResolveAndMarkLoading","onQueryInput","forceCreateFromInput","newTag","tagExists","newIsOpen","oldIsOpen","useAvatarSizeClasses","heightClasses","textClasses","initials","parts","firstLetter","secondLetter","_d","borderClasses","bgClasses","hoverClasses","activeClasses","maxCountHiddenItemCount","visibleUsers","limit","maxAvatarsHiddenCount","totalHiddenCount","LazyUserAvatarEditor","defineAsyncComponent","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","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","keyboardClickableKeypressHandler","vKeyboardClickable","percentage","colorClass"],"mappings":"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","x_google_ignoreList":[40,41,42,43,44,45,46,47,48,49,50,51,52,53,54]}