@scalar/components 0.27.1 → 0.27.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ScalarTextArea.vue.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none border-none bg-transparent text-sm focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"ScalarTextArea.vue.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":""}
@@ -21,12 +21,12 @@ var ScalarTextArea_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */
21
21
  if ("autofocus" in otherAttrs.value) textarea.value?.focus();
22
22
  });
23
23
  return (_ctx, _cache) => {
24
- return openBlock(), createBlock(unref(ScalarFormInput_default), mergeProps({ is: "div" }, unref(stylingAttrsCx)("custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug"), { onClick: _cache[1] || (_cache[1] = ($event) => unref(textarea)?.focus()) }), {
24
+ return openBlock(), createBlock(unref(ScalarFormInput_default), mergeProps({ is: "div" }, unref(stylingAttrsCx)("custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1"), { onClick: _cache[1] || (_cache[1] = ($event) => unref(textarea)?.focus()) }), {
25
25
  default: withCtx(() => [withDirectives(createElementVNode("textarea", mergeProps({
26
26
  ref_key: "textarea",
27
27
  ref: textarea,
28
28
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => model.value = $event)
29
- }, unref(otherAttrs), { class: "w-full resize-none border-none bg-transparent text-sm focus-within:outline-none" }), null, 16), [[vModelText, model.value]])]),
29
+ }, unref(otherAttrs), { class: "w-full resize-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none" }), null, 16), [[vModelText, model.value]])]),
30
30
  _: 1
31
31
  }, 16);
32
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ScalarTextArea.vue.script.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none border-none bg-transparent text-sm focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":";;;;;;;;;;;;;EAkBA,MAAM,QAAQ,SAAmB,SAAA,aAAgB;EAEjD,MAAM,EAAE,aAAa,oBAAoB;GACvC,OAAO;GACP,WAAW;GACZ,CAAA;EAGD,MAAM,EAAE,gBAAgB,eAAe,WAAU;AAEjD,kBAAgB;AAEd,OAAI,eAAe,WAAW,MAAO,UAAS,OAAO,OAAM;IAC5D;;uBAGC,YAakB,MAAA,wBAAA,EAblB,WAakB,EAZhB,IAAG,OAAK,EACO,MAAA,eAAc,CAAA,kFAAA,EAAA,EAK5B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,SAAQ,EAAE,OAAK,GAAA,CAAA,EAAA;2BAKqE,CAAA,eAJ5F,mBAI4F,YAJ5F,WAI4F;cAHtF;KAAJ,KAAI;wEACU,QAAA;OACN,MAAA,WAAU,EAAA,EAClB,OAAM,mFAAiF,CAAA,EAAA,MAAA,GAAA,EAAA,CAAA,CAAA,YAF9E,MAAA,MAAK,CAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"ScalarTextArea.vue.script.js","names":[],"sources":["../../../src/components/ScalarTextArea/ScalarTextArea.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Text Area component\n *\n * A wrapper around the HTML textarea element with a focusable container.\n *\n * @example\n * <ScalarTextArea v-model=\"model\" />\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { useTextareaAutosize } from '@vueuse/core'\nimport { onMounted } from 'vue'\n\nimport { ScalarFormInput } from '../ScalarForm'\n\nconst model = defineModel<string>({ default: '' })\n\nconst { textarea } = useTextareaAutosize({\n input: model,\n styleProp: 'minHeight',\n})\n\ndefineOptions({ inheritAttrs: false })\nconst { stylingAttrsCx, otherAttrs } = useBindCx()\n\nonMounted(() => {\n // Force autofocus if the textarea has the autofocus attribute\n if ('autofocus' in otherAttrs.value) textarea.value?.focus()\n})\n</script>\n<template>\n <ScalarFormInput\n is=\"div\"\n v-bind=\"\n stylingAttrsCx(\n 'custom-scroll flex items-start text-c-1 min-h-0 shrink cursor-text leading-snug focus-within:bg-b-1',\n )\n \"\n @click=\"textarea?.focus()\">\n <textarea\n ref=\"textarea\"\n v-model=\"model\"\n v-bind=\"otherAttrs\"\n class=\"w-full resize-none border-none bg-transparent placeholder:font-[inherit] focus-within:outline-none\" />\n </ScalarFormInput>\n</template>\n"],"mappings":";;;;;;;;;;;;;EAkBA,MAAM,QAAQ,SAAmB,SAAA,aAAgB;EAEjD,MAAM,EAAE,aAAa,oBAAoB;GACvC,OAAO;GACP,WAAW;GACZ,CAAA;EAGD,MAAM,EAAE,gBAAgB,eAAe,WAAU;AAEjD,kBAAgB;AAEd,OAAI,eAAe,WAAW,MAAO,UAAS,OAAO,OAAM;IAC5D;;uBAGC,YAakB,MAAA,wBAAA,EAblB,WAakB,EAZhB,IAAG,OAAK,EACO,MAAA,eAAc,CAAA,sGAAA,EAAA,EAK5B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,MAAA,SAAQ,EAAE,OAAK,GAAA,CAAA,EAAA;2BAKwF,CAAA,eAJ/G,mBAI+G,YAJ/G,WAI+G;cAHzG;KAAJ,KAAI;wEACU,QAAA;OACN,MAAA,WAAU,EAAA,EAClB,OAAM,sGAAoG,CAAA,EAAA,MAAA,GAAA,EAAA,CAAA,CAAA,YAFjG,MAAA,MAAK,CAAA,CAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScalarTooltip.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarTooltip/ScalarTooltip.vue"],"names":[],"mappings":"AAwEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAIjD;;;;;;;;;GASG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;cA6CJ,CAAC,KAAK,IAAgB,KAAK,GAAG;EAWxC,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"ScalarTooltip.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarTooltip/ScalarTooltip.vue"],"names":[],"mappings":"AAmHA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAIjD;;;;;;;;;GASG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;cA6CJ,CAAC,KAAK,IAAgB,KAAK,GAAG;EAWxC,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScalarTooltip.vue.js","names":[],"sources":["../../../src/components/ScalarTooltip/ScalarTooltip.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar tooltip component\n *\n * Adds a tooltip to an interactive element\n *\n * @example\n * <ScalarTooltip content=\"This is a tooltip\">\n * <ScalarButton>Hover Me</ScalarButton>\n * </ScalarTooltip>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { type Ref, computed, ref } from 'vue'\n\nimport { DEFAULT_DELAY, DEFAULT_OFFSET } from './constants'\nimport type { ScalarTooltipProps } from './types'\nimport { useTooltip } from './useTooltip'\n\nconst {\n delay = DEFAULT_DELAY,\n content = '',\n placement = 'top',\n offset = DEFAULT_OFFSET,\n} = defineProps<ScalarTooltipProps>()\n\nconst wrapperRef: Ref<HTMLElement | null> = ref(null)\n\nuseTooltip({\n content: computed(() => content),\n delay: computed(() => delay),\n placement: computed(() => placement),\n offset: computed(() => offset),\n targetRef: computed(\n () => wrapperRef.value?.children?.[0] || wrapperRef.value || undefined,\n ),\n})\n</script>\n<template>\n <div\n ref=\"wrapperRef\"\n :class=\"{ contents: !!$slots.default }\">\n <slot />\n </div>\n</template>\n<style>\n@reference \"../../style.css\";\n\n/** Global styles for the tooltip */\n:where(body) > .scalar-tooltip {\n --scalar-tooltip-padding: 8px;\n\n padding: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));\n\n @apply z-tooltip text-c-tooltip text-xs/4 font-medium break-words max-w-xs;\n}\n:where(body) > .scalar-tooltip:before {\n content: '';\n inset: var(--scalar-tooltip-offset);\n @apply absolute rounded bg-b-tooltip -z-1 backdrop-blur;\n}\n:where(body.dark-mode) > .scalar-tooltip:before {\n @apply shadow-border;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"ScalarTooltip.vue.js","names":[],"sources":["../../../src/components/ScalarTooltip/ScalarTooltip.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar tooltip component\n *\n * Adds a tooltip to an interactive element\n *\n * @example\n * <ScalarTooltip content=\"This is a tooltip\">\n * <ScalarButton>Hover Me</ScalarButton>\n * </ScalarTooltip>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { type Ref, computed, ref } from 'vue'\n\nimport { DEFAULT_DELAY, DEFAULT_OFFSET } from './constants'\nimport type { ScalarTooltipProps } from './types'\nimport { useTooltip } from './useTooltip'\n\nconst {\n delay = DEFAULT_DELAY,\n content = '',\n placement = 'top',\n offset = DEFAULT_OFFSET,\n} = defineProps<ScalarTooltipProps>()\n\nconst wrapperRef: Ref<HTMLElement | null> = ref(null)\n\nuseTooltip({\n content: computed(() => content),\n delay: computed(() => delay),\n placement: computed(() => placement),\n offset: computed(() => offset),\n targetRef: computed(\n () => wrapperRef.value?.children?.[0] || wrapperRef.value || undefined,\n ),\n})\n</script>\n<template>\n <div\n ref=\"wrapperRef\"\n :class=\"{ contents: !!$slots.default }\">\n <slot />\n </div>\n</template>\n<style>\n@reference \"../../style.css\";\n\n/** Global styles for the tooltip */\n:where(body) > .scalar-tooltip {\n --scalar-tooltip-padding: 8px;\n\n padding: var(--scalar-tooltip-padding);\n\n @apply z-tooltip text-c-tooltip text-xs/4 font-medium break-words max-w-xs;\n}\n\n/**\n * The offset is the gap between the target and the tooltip, so it only belongs\n * on the side facing the target (opposite the placement side). Applying it to\n * every side shifts the visible box inward on `-start` / `-end` placements,\n * where Floating UI aligns the floating element's edge with the target's edge.\n */\n:where(body) > .scalar-tooltip[data-side='top'] {\n padding-bottom: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n:where(body) > .scalar-tooltip[data-side='bottom'] {\n padding-top: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n:where(body) > .scalar-tooltip[data-side='left'] {\n padding-right: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n:where(body) > .scalar-tooltip[data-side='right'] {\n padding-left: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n\n:where(body) > .scalar-tooltip:before {\n content: '';\n inset: 0;\n @apply absolute rounded bg-b-tooltip -z-1 backdrop-blur;\n}\n\n/* Leave the gap on the target-facing side so the other edges stay flush */\n:where(body) > .scalar-tooltip[data-side='top']:before {\n bottom: var(--scalar-tooltip-offset);\n}\n:where(body) > .scalar-tooltip[data-side='bottom']:before {\n top: var(--scalar-tooltip-offset);\n}\n:where(body) > .scalar-tooltip[data-side='left']:before {\n right: var(--scalar-tooltip-offset);\n}\n:where(body) > .scalar-tooltip[data-side='right']:before {\n left: var(--scalar-tooltip-offset);\n}\n\n:where(body.dark-mode) > .scalar-tooltip:before {\n @apply shadow-border;\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"ScalarTooltip.vue.script.js","names":["$slots"],"sources":["../../../src/components/ScalarTooltip/ScalarTooltip.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar tooltip component\n *\n * Adds a tooltip to an interactive element\n *\n * @example\n * <ScalarTooltip content=\"This is a tooltip\">\n * <ScalarButton>Hover Me</ScalarButton>\n * </ScalarTooltip>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { type Ref, computed, ref } from 'vue'\n\nimport { DEFAULT_DELAY, DEFAULT_OFFSET } from './constants'\nimport type { ScalarTooltipProps } from './types'\nimport { useTooltip } from './useTooltip'\n\nconst {\n delay = DEFAULT_DELAY,\n content = '',\n placement = 'top',\n offset = DEFAULT_OFFSET,\n} = defineProps<ScalarTooltipProps>()\n\nconst wrapperRef: Ref<HTMLElement | null> = ref(null)\n\nuseTooltip({\n content: computed(() => content),\n delay: computed(() => delay),\n placement: computed(() => placement),\n offset: computed(() => offset),\n targetRef: computed(\n () => wrapperRef.value?.children?.[0] || wrapperRef.value || undefined,\n ),\n})\n</script>\n<template>\n <div\n ref=\"wrapperRef\"\n :class=\"{ contents: !!$slots.default }\">\n <slot />\n </div>\n</template>\n<style>\n@reference \"../../style.css\";\n\n/** Global styles for the tooltip */\n:where(body) > .scalar-tooltip {\n --scalar-tooltip-padding: 8px;\n\n padding: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));\n\n @apply z-tooltip text-c-tooltip text-xs/4 font-medium break-words max-w-xs;\n}\n:where(body) > .scalar-tooltip:before {\n content: '';\n inset: var(--scalar-tooltip-offset);\n @apply absolute rounded bg-b-tooltip -z-1 backdrop-blur;\n}\n:where(body.dark-mode) > .scalar-tooltip:before {\n @apply shadow-border;\n}\n</style>\n"],"mappings":";;;;;;;;;;;EA2BA,MAAM,aAAsC,IAAI,KAAI;AAEpD,aAAW;GACT,SAAS,eAAe,QAAA,QAAQ;GAChC,OAAO,eAAe,QAAA,MAAM;GAC5B,WAAW,eAAe,QAAA,UAAU;GACpC,QAAQ,eAAe,QAAA,OAAO;GAC9B,WAAW,eACH,WAAW,OAAO,WAAW,MAAM,WAAW,SAAS,KAAA,EAC9D;GACF,CAAA;;uBAGC,mBAIM,OAAA;aAHA;IAAJ,KAAI;IACH,OAAK,eAAA,EAAA,UAAA,CAAA,CAAgBA,KAAAA,OAAO,SAAO,CAAA;OACpC,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,EAAA"}
1
+ {"version":3,"file":"ScalarTooltip.vue.script.js","names":["$slots"],"sources":["../../../src/components/ScalarTooltip/ScalarTooltip.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar tooltip component\n *\n * Adds a tooltip to an interactive element\n *\n * @example\n * <ScalarTooltip content=\"This is a tooltip\">\n * <ScalarButton>Hover Me</ScalarButton>\n * </ScalarTooltip>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { type Ref, computed, ref } from 'vue'\n\nimport { DEFAULT_DELAY, DEFAULT_OFFSET } from './constants'\nimport type { ScalarTooltipProps } from './types'\nimport { useTooltip } from './useTooltip'\n\nconst {\n delay = DEFAULT_DELAY,\n content = '',\n placement = 'top',\n offset = DEFAULT_OFFSET,\n} = defineProps<ScalarTooltipProps>()\n\nconst wrapperRef: Ref<HTMLElement | null> = ref(null)\n\nuseTooltip({\n content: computed(() => content),\n delay: computed(() => delay),\n placement: computed(() => placement),\n offset: computed(() => offset),\n targetRef: computed(\n () => wrapperRef.value?.children?.[0] || wrapperRef.value || undefined,\n ),\n})\n</script>\n<template>\n <div\n ref=\"wrapperRef\"\n :class=\"{ contents: !!$slots.default }\">\n <slot />\n </div>\n</template>\n<style>\n@reference \"../../style.css\";\n\n/** Global styles for the tooltip */\n:where(body) > .scalar-tooltip {\n --scalar-tooltip-padding: 8px;\n\n padding: var(--scalar-tooltip-padding);\n\n @apply z-tooltip text-c-tooltip text-xs/4 font-medium break-words max-w-xs;\n}\n\n/**\n * The offset is the gap between the target and the tooltip, so it only belongs\n * on the side facing the target (opposite the placement side). Applying it to\n * every side shifts the visible box inward on `-start` / `-end` placements,\n * where Floating UI aligns the floating element's edge with the target's edge.\n */\n:where(body) > .scalar-tooltip[data-side='top'] {\n padding-bottom: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n:where(body) > .scalar-tooltip[data-side='bottom'] {\n padding-top: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n:where(body) > .scalar-tooltip[data-side='left'] {\n padding-right: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n:where(body) > .scalar-tooltip[data-side='right'] {\n padding-left: calc(\n var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset)\n );\n}\n\n:where(body) > .scalar-tooltip:before {\n content: '';\n inset: 0;\n @apply absolute rounded bg-b-tooltip -z-1 backdrop-blur;\n}\n\n/* Leave the gap on the target-facing side so the other edges stay flush */\n:where(body) > .scalar-tooltip[data-side='top']:before {\n bottom: var(--scalar-tooltip-offset);\n}\n:where(body) > .scalar-tooltip[data-side='bottom']:before {\n top: var(--scalar-tooltip-offset);\n}\n:where(body) > .scalar-tooltip[data-side='left']:before {\n right: var(--scalar-tooltip-offset);\n}\n:where(body) > .scalar-tooltip[data-side='right']:before {\n left: var(--scalar-tooltip-offset);\n}\n\n:where(body.dark-mode) > .scalar-tooltip:before {\n @apply shadow-border;\n}\n</style>\n"],"mappings":";;;;;;;;;;;EA2BA,MAAM,aAAsC,IAAI,KAAI;AAEpD,aAAW;GACT,SAAS,eAAe,QAAA,QAAQ;GAChC,OAAO,eAAe,QAAA,MAAM;GAC5B,WAAW,eAAe,QAAA,UAAU;GACpC,QAAQ,eAAe,QAAA,OAAO;GAC9B,WAAW,eACH,WAAW,OAAO,WAAW,MAAM,WAAW,SAAS,KAAA,EAC9D;GACF,CAAA;;uBAGC,mBAIM,OAAA;aAHA;IAAJ,KAAI;IACH,OAAK,eAAA,EAAA,UAAA,CAAA,CAAgBA,KAAAA,OAAO,SAAO,CAAA;OACpC,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,EAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTooltip.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarTooltip/useTooltip.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAS,oBAAoB,EAAE,MAAM,SAAS,CAAA;AA4H1D;;GAEG;AACH,wBAAgB,qBAAqB,SAGpC;AA2ED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,oBAAoB,QAwEpD"}
1
+ {"version":3,"file":"useTooltip.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarTooltip/useTooltip.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAS,oBAAoB,EAAE,MAAM,SAAS,CAAA;AA+I1D;;GAEG;AACH,wBAAgB,qBAAqB,SAGpC;AA2ED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,oBAAoB,QAwEpD"}
@@ -20,11 +20,15 @@ var el = ref();
20
20
  * If no tooltip is active it should be undefined
21
21
  */
22
22
  var config = ref();
23
- var { floatingStyles } = useFloating(computed(() => unref(config.value?.targetRef)), el, {
23
+ var { floatingStyles, placement } = useFloating(computed(() => unref(config.value?.targetRef)), el, {
24
24
  placement: computed(() => unref(config.value?.placement)),
25
25
  whileElementsMounted: autoUpdate,
26
26
  middleware: computed(() => [flip(), shift()])
27
27
  });
28
+ watch(placement, (value) => {
29
+ if (!el.value || !value) return;
30
+ el.value.dataset.side = value.split("-")[0];
31
+ });
28
32
  watch(floatingStyles, () => {
29
33
  if (!el.value) return;
30
34
  el.value.style.position = floatingStyles.value.position;
@@ -40,6 +44,7 @@ watch(config, (opts) => {
40
44
  el.value[contentTarget] = unref(opts?.content) ?? "";
41
45
  const offset = unref(opts?.offset) ?? 4;
42
46
  el.value.style.setProperty("--scalar-tooltip-offset", `${offset}px`);
47
+ el.value.dataset.side = (unref(opts?.placement) ?? "bottom").split("-")[0];
43
48
  el.value.style.setProperty("display", "block");
44
49
  } else {
45
50
  el.value.innerHTML = "";
@@ -1 +1 @@
1
- {"version":3,"file":"useTooltip.js","names":[],"sources":["../../../src/components/ScalarTooltip/useTooltip.ts"],"sourcesContent":["import { autoUpdate, flip, shift, useFloating } from '@floating-ui/vue'\nimport { computed, onScopeDispose, ref, unref, watch } from 'vue'\n\nimport { DEFAULT_DELAY, DEFAULT_OFFSET, ELEMENT_CLASS, ELEMENT_ID } from './constants'\nimport type { Timer, TooltipConfiguration } from './types'\n\n// ---------------------------------------------------------------------------\n// State\n// ---------------------------------------------------------------------------\n\n/**\n * The delay timer for the tooltip\n *\n * If there's not a timer running it should be undefined\n */\nconst timer = ref<Timer>()\n\n/**\n * A reference to the tooltip element\n *\n * If the hook hasn't been initialized it should be undefined\n */\nconst el = ref<HTMLElement>()\n\n/**\n * The configuration for the active tooltip\n *\n * If no tooltip is active it should be undefined\n */\nconst config = ref<TooltipConfiguration>()\n\n// ---------------------------------------------------------------------------\n// Core watcher and floating UI setup\n// ---------------------------------------------------------------------------\n\n// Set up floating UI\nconst { floatingStyles } = useFloating(\n computed(() => unref(config.value?.targetRef)),\n el,\n {\n placement: computed(() => unref(config.value?.placement)),\n whileElementsMounted: autoUpdate,\n middleware: computed(() => [flip(), shift()]),\n },\n)\n\n// Update the tooltip element's positioning when Floating UI updates the styles\nwatch(floatingStyles, () => {\n if (!el.value) {\n return\n }\n\n el.value.style.position = floatingStyles.value.position\n el.value.style.top = floatingStyles.value.top\n el.value.style.left = floatingStyles.value.left\n el.value.style.transform = floatingStyles.value.transform ?? ''\n el.value.style.willChange = floatingStyles.value.willChange ?? ''\n})\n\n// Show or hide the tooltip when the config changes\nwatch(\n config,\n (opts) => {\n if (!el.value) {\n return\n }\n\n if (opts) {\n const contentTarget = unref(opts?.contentTarget) ?? 'textContent'\n\n // Update the tooltip content\n el.value[contentTarget] = unref(opts?.content) ?? ''\n\n // Show the tooltip\n const offset = unref(opts?.offset) ?? DEFAULT_OFFSET\n el.value.style.setProperty('--scalar-tooltip-offset', `${offset}px`)\n el.value.style.setProperty('display', 'block')\n } else {\n // Clear the tooltip content\n el.value.innerHTML = ''\n\n // Hide the tooltip\n el.value.style.removeProperty('--scalar-tooltip-offset')\n el.value.style.setProperty('display', 'none')\n }\n },\n { deep: true },\n)\n\n// ---------------------------------------------------------------------------\n// Lifecycle Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Initialize the tooltip element\n *\n * If the tooltip is already initialized it will be ignored\n */\nfunction initializeTooltipElement(): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n // Skip tooltip initialization during SSR\n return\n }\n\n if (el.value) {\n // Tooltip already initialized\n return\n }\n\n // See if the tooltip element already exists\n // (Sometimes this happens with HMR)\n const existingTooltipElement = document.getElementById(ELEMENT_ID)\n\n if (existingTooltipElement) {\n el.value = existingTooltipElement\n } else {\n // Create the tooltip element\n el.value = document.createElement('div')\n el.value.role = 'tooltip'\n el.value.id = ELEMENT_ID\n el.value.classList.add(ELEMENT_CLASS)\n el.value.classList.add('scalar-app')\n el.value.style.setProperty('display', 'none')\n el.value.addEventListener('mouseleave', hideTooltip)\n document.body.appendChild(el.value)\n }\n}\n\n/**\n * Cleanup and reset the tooltip element\n */\nexport function cleanupTooltipElement() {\n document.getElementById(ELEMENT_ID)?.remove()\n el.value = undefined\n}\n\n// ---------------------------------------------------------------------------\n// Helper Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Hide the tooltip\n *\n * If the mouse is moving between the tooltip and the target we don't hide the tooltip\n */\nfunction hideTooltip(_e: Event) {\n if (!isMovingOffElements(_e)) {\n // Don't hide the tooltip if the mouse is moving between the tooltip and the target\n return\n }\n\n // Clear any existing timer\n clearTimer()\n\n // Hide the tooltip\n config.value = undefined\n}\n\n/**\n * Handle the escape key\n *\n * If the escape key is pressed we need to hide the tooltip\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tooltip_role#keyboard_interactions\n */\nfunction handleEscape(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n e.stopPropagation()\n hideTooltip(e)\n }\n}\n\n/** Clears the current timer */\nfunction clearTimer() {\n if (timer.value) {\n clearTimeout(timer.value)\n timer.value = undefined\n }\n}\n\n/** Get all the parents of an element */\nfunction getAllParents(el: Element): Element[] {\n const parents: Element[] = []\n let parent = el.parentElement\n while (parent) {\n parents.push(parent)\n parent = parent.parentElement\n }\n return parents\n}\n\n/** Check if mouse moved off the target but onto the tooltip */\nfunction isMovingOffElements(e: Event): boolean {\n const target = unref(config.value?.targetRef)\n if (e instanceof MouseEvent && e.relatedTarget instanceof Element && target) {\n const relatedTargetParents = getAllParents(e.relatedTarget)\n return (\n e.relatedTarget.id !== ELEMENT_ID &&\n !relatedTargetParents.some((parent) => parent.id === ELEMENT_ID) &&\n e.relatedTarget !== target\n )\n }\n return true\n}\n\n// ---------------------------------------------------------------------------\n// Tooltip Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Create a tooltip\n *\n * If there isn't a tooltip element it will be created\n */\nexport function useTooltip(opts: TooltipConfiguration) {\n initializeTooltipElement()\n\n /**\n * Show the tooltip after the delay if configured\n */\n function showTooltipAfterDelay(_e: Event) {\n const delay = unref(opts.delay) ?? DEFAULT_DELAY\n clearTimer()\n\n // Show the tooltip after the delay\n if (delay > 0) {\n timer.value = setTimeout(() => showTooltip(_e), delay)\n } else {\n showTooltip(_e)\n }\n }\n\n /**\n * Show the tooltip\n */\n function showTooltip(_e: Event) {\n clearTimer()\n\n // Handle the escape key\n document.addEventListener('keydown', handleEscape, { once: true, capture: true })\n\n // Show the tooltip\n config.value = opts\n }\n\n watch(\n () => unref(opts.targetRef),\n (newRef, oldRef) => {\n if (oldRef) {\n oldRef.removeEventListener('mouseenter', showTooltipAfterDelay)\n oldRef.removeEventListener('mouseleave', hideTooltip)\n oldRef.removeEventListener('focus', showTooltip)\n oldRef.removeEventListener('blur', hideTooltip)\n\n oldRef.removeAttribute('aria-describedby')\n }\n if (newRef) {\n newRef.addEventListener('mouseenter', showTooltipAfterDelay)\n newRef.addEventListener('mouseleave', hideTooltip)\n newRef.addEventListener('focus', showTooltip)\n newRef.addEventListener('blur', hideTooltip)\n\n newRef.setAttribute('aria-describedby', ELEMENT_ID)\n }\n },\n { immediate: true },\n )\n\n // Cleanup the tooltip when the component is unmounted\n onScopeDispose(() => {\n clearTimer()\n\n const target = unref(opts.targetRef)\n if (target) {\n target.removeEventListener('mouseenter', showTooltipAfterDelay)\n target.removeEventListener('mouseleave', hideTooltip)\n target.removeEventListener('focus', showTooltip)\n target.removeEventListener('blur', hideTooltip)\n target.removeAttribute('aria-describedby')\n }\n\n // If the tooltip is showing on this target hide it\n if (unref(config.value?.targetRef) === unref(opts.targetRef)) {\n config.value = undefined\n }\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useTooltip.js","names":[],"sources":["../../../src/components/ScalarTooltip/useTooltip.ts"],"sourcesContent":["import { autoUpdate, flip, shift, useFloating } from '@floating-ui/vue'\nimport { computed, onScopeDispose, ref, unref, watch } from 'vue'\n\nimport { DEFAULT_DELAY, DEFAULT_OFFSET, ELEMENT_CLASS, ELEMENT_ID } from './constants'\nimport type { Timer, TooltipConfiguration } from './types'\n\n// ---------------------------------------------------------------------------\n// State\n// ---------------------------------------------------------------------------\n\n/**\n * The delay timer for the tooltip\n *\n * If there's not a timer running it should be undefined\n */\nconst timer = ref<Timer>()\n\n/**\n * A reference to the tooltip element\n *\n * If the hook hasn't been initialized it should be undefined\n */\nconst el = ref<HTMLElement>()\n\n/**\n * The configuration for the active tooltip\n *\n * If no tooltip is active it should be undefined\n */\nconst config = ref<TooltipConfiguration>()\n\n// ---------------------------------------------------------------------------\n// Core watcher and floating UI setup\n// ---------------------------------------------------------------------------\n\n// Set up floating UI\nconst { floatingStyles, placement } = useFloating(\n computed(() => unref(config.value?.targetRef)),\n el,\n {\n placement: computed(() => unref(config.value?.placement)),\n whileElementsMounted: autoUpdate,\n middleware: computed(() => [flip(), shift()]),\n },\n)\n\n// Expose the resolved placement side (post-flip) so the CSS can apply the offset\n// gap only on the side facing the target. We key off the side (the part before\n// the '-') because that is where the tooltip sits relative to the target. The\n// initial side is set synchronously when the tooltip is shown (see the config\n// watcher below); this watcher keeps it in sync once Floating UI flips it.\nwatch(placement, (value) => {\n if (!el.value || !value) {\n return\n }\n el.value.dataset.side = value.split('-')[0]\n})\n\n// Update the tooltip element's positioning when Floating UI updates the styles\nwatch(floatingStyles, () => {\n if (!el.value) {\n return\n }\n\n el.value.style.position = floatingStyles.value.position\n el.value.style.top = floatingStyles.value.top\n el.value.style.left = floatingStyles.value.left\n el.value.style.transform = floatingStyles.value.transform ?? ''\n el.value.style.willChange = floatingStyles.value.willChange ?? ''\n})\n\n// Show or hide the tooltip when the config changes\nwatch(\n config,\n (opts) => {\n if (!el.value) {\n return\n }\n\n if (opts) {\n const contentTarget = unref(opts?.contentTarget) ?? 'textContent'\n\n // Update the tooltip content\n el.value[contentTarget] = unref(opts?.content) ?? ''\n\n // Show the tooltip\n const offset = unref(opts?.offset) ?? DEFAULT_OFFSET\n el.value.style.setProperty('--scalar-tooltip-offset', `${offset}px`)\n\n // Set the side the tooltip sits on so the offset gap is only applied to\n // the target-facing side. Floating UI defaults to 'bottom' when no\n // placement is provided; the placement watcher above refines this after\n // any flip.\n el.value.dataset.side = (unref(opts?.placement) ?? 'bottom').split('-')[0]\n\n el.value.style.setProperty('display', 'block')\n } else {\n // Clear the tooltip content\n el.value.innerHTML = ''\n\n // Hide the tooltip\n el.value.style.removeProperty('--scalar-tooltip-offset')\n el.value.style.setProperty('display', 'none')\n }\n },\n { deep: true },\n)\n\n// ---------------------------------------------------------------------------\n// Lifecycle Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Initialize the tooltip element\n *\n * If the tooltip is already initialized it will be ignored\n */\nfunction initializeTooltipElement(): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n // Skip tooltip initialization during SSR\n return\n }\n\n if (el.value) {\n // Tooltip already initialized\n return\n }\n\n // See if the tooltip element already exists\n // (Sometimes this happens with HMR)\n const existingTooltipElement = document.getElementById(ELEMENT_ID)\n\n if (existingTooltipElement) {\n el.value = existingTooltipElement\n } else {\n // Create the tooltip element\n el.value = document.createElement('div')\n el.value.role = 'tooltip'\n el.value.id = ELEMENT_ID\n el.value.classList.add(ELEMENT_CLASS)\n el.value.classList.add('scalar-app')\n el.value.style.setProperty('display', 'none')\n el.value.addEventListener('mouseleave', hideTooltip)\n document.body.appendChild(el.value)\n }\n}\n\n/**\n * Cleanup and reset the tooltip element\n */\nexport function cleanupTooltipElement() {\n document.getElementById(ELEMENT_ID)?.remove()\n el.value = undefined\n}\n\n// ---------------------------------------------------------------------------\n// Helper Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Hide the tooltip\n *\n * If the mouse is moving between the tooltip and the target we don't hide the tooltip\n */\nfunction hideTooltip(_e: Event) {\n if (!isMovingOffElements(_e)) {\n // Don't hide the tooltip if the mouse is moving between the tooltip and the target\n return\n }\n\n // Clear any existing timer\n clearTimer()\n\n // Hide the tooltip\n config.value = undefined\n}\n\n/**\n * Handle the escape key\n *\n * If the escape key is pressed we need to hide the tooltip\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/tooltip_role#keyboard_interactions\n */\nfunction handleEscape(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n e.stopPropagation()\n hideTooltip(e)\n }\n}\n\n/** Clears the current timer */\nfunction clearTimer() {\n if (timer.value) {\n clearTimeout(timer.value)\n timer.value = undefined\n }\n}\n\n/** Get all the parents of an element */\nfunction getAllParents(el: Element): Element[] {\n const parents: Element[] = []\n let parent = el.parentElement\n while (parent) {\n parents.push(parent)\n parent = parent.parentElement\n }\n return parents\n}\n\n/** Check if mouse moved off the target but onto the tooltip */\nfunction isMovingOffElements(e: Event): boolean {\n const target = unref(config.value?.targetRef)\n if (e instanceof MouseEvent && e.relatedTarget instanceof Element && target) {\n const relatedTargetParents = getAllParents(e.relatedTarget)\n return (\n e.relatedTarget.id !== ELEMENT_ID &&\n !relatedTargetParents.some((parent) => parent.id === ELEMENT_ID) &&\n e.relatedTarget !== target\n )\n }\n return true\n}\n\n// ---------------------------------------------------------------------------\n// Tooltip Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Create a tooltip\n *\n * If there isn't a tooltip element it will be created\n */\nexport function useTooltip(opts: TooltipConfiguration) {\n initializeTooltipElement()\n\n /**\n * Show the tooltip after the delay if configured\n */\n function showTooltipAfterDelay(_e: Event) {\n const delay = unref(opts.delay) ?? DEFAULT_DELAY\n clearTimer()\n\n // Show the tooltip after the delay\n if (delay > 0) {\n timer.value = setTimeout(() => showTooltip(_e), delay)\n } else {\n showTooltip(_e)\n }\n }\n\n /**\n * Show the tooltip\n */\n function showTooltip(_e: Event) {\n clearTimer()\n\n // Handle the escape key\n document.addEventListener('keydown', handleEscape, { once: true, capture: true })\n\n // Show the tooltip\n config.value = opts\n }\n\n watch(\n () => unref(opts.targetRef),\n (newRef, oldRef) => {\n if (oldRef) {\n oldRef.removeEventListener('mouseenter', showTooltipAfterDelay)\n oldRef.removeEventListener('mouseleave', hideTooltip)\n oldRef.removeEventListener('focus', showTooltip)\n oldRef.removeEventListener('blur', hideTooltip)\n\n oldRef.removeAttribute('aria-describedby')\n }\n if (newRef) {\n newRef.addEventListener('mouseenter', showTooltipAfterDelay)\n newRef.addEventListener('mouseleave', hideTooltip)\n newRef.addEventListener('focus', showTooltip)\n newRef.addEventListener('blur', hideTooltip)\n\n newRef.setAttribute('aria-describedby', ELEMENT_ID)\n }\n },\n { immediate: true },\n )\n\n // Cleanup the tooltip when the component is unmounted\n onScopeDispose(() => {\n clearTimer()\n\n const target = unref(opts.targetRef)\n if (target) {\n target.removeEventListener('mouseenter', showTooltipAfterDelay)\n target.removeEventListener('mouseleave', hideTooltip)\n target.removeEventListener('focus', showTooltip)\n target.removeEventListener('blur', hideTooltip)\n target.removeAttribute('aria-describedby')\n }\n\n // If the tooltip is showing on this target hide it\n if (unref(config.value?.targetRef) === unref(opts.targetRef)) {\n config.value = undefined\n }\n })\n}\n"],"mappings":";;;;;;;;;AAeA,IAAM,QAAQ,KAAY;;;;;;AAO1B,IAAM,KAAK,KAAkB;;;;;;AAO7B,IAAM,SAAS,KAA2B;AAO1C,IAAM,EAAE,gBAAgB,cAAc,YACpC,eAAe,MAAM,OAAO,OAAO,UAAU,CAAC,EAC9C,IACA;CACE,WAAW,eAAe,MAAM,OAAO,OAAO,UAAU,CAAC;CACzD,sBAAsB;CACtB,YAAY,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C,CACF;AAOD,MAAM,YAAY,UAAU;AAC1B,KAAI,CAAC,GAAG,SAAS,CAAC,MAChB;AAEF,IAAG,MAAM,QAAQ,OAAO,MAAM,MAAM,IAAI,CAAC;EACzC;AAGF,MAAM,sBAAsB;AAC1B,KAAI,CAAC,GAAG,MACN;AAGF,IAAG,MAAM,MAAM,WAAW,eAAe,MAAM;AAC/C,IAAG,MAAM,MAAM,MAAM,eAAe,MAAM;AAC1C,IAAG,MAAM,MAAM,OAAO,eAAe,MAAM;AAC3C,IAAG,MAAM,MAAM,YAAY,eAAe,MAAM,aAAa;AAC7D,IAAG,MAAM,MAAM,aAAa,eAAe,MAAM,cAAc;EAC/D;AAGF,MACE,SACC,SAAS;AACR,KAAI,CAAC,GAAG,MACN;AAGF,KAAI,MAAM;EACR,MAAM,gBAAgB,MAAM,MAAM,cAAc,IAAI;AAGpD,KAAG,MAAM,iBAAiB,MAAM,MAAM,QAAQ,IAAI;EAGlD,MAAM,SAAS,MAAM,MAAM,OAAO,IAAA;AAClC,KAAG,MAAM,MAAM,YAAY,2BAA2B,GAAG,OAAO,IAAI;AAMpE,KAAG,MAAM,QAAQ,QAAQ,MAAM,MAAM,UAAU,IAAI,UAAU,MAAM,IAAI,CAAC;AAExE,KAAG,MAAM,MAAM,YAAY,WAAW,QAAQ;QACzC;AAEL,KAAG,MAAM,YAAY;AAGrB,KAAG,MAAM,MAAM,eAAe,0BAA0B;AACxD,KAAG,MAAM,MAAM,YAAY,WAAW,OAAO;;GAGjD,EAAE,MAAM,MAAM,CACf;;;;;;AAWD,SAAS,2BAAiC;AACxC,KAAI,OAAO,aAAa,eAAe,OAAO,WAAW,YAEvD;AAGF,KAAI,GAAG,MAEL;CAKF,MAAM,yBAAyB,SAAS,eAAe,WAAW;AAElE,KAAI,uBACF,IAAG,QAAQ;MACN;AAEL,KAAG,QAAQ,SAAS,cAAc,MAAM;AACxC,KAAG,MAAM,OAAO;AAChB,KAAG,MAAM,KAAK;AACd,KAAG,MAAM,UAAU,IAAI,cAAc;AACrC,KAAG,MAAM,UAAU,IAAI,aAAa;AACpC,KAAG,MAAM,MAAM,YAAY,WAAW,OAAO;AAC7C,KAAG,MAAM,iBAAiB,cAAc,YAAY;AACpD,WAAS,KAAK,YAAY,GAAG,MAAM;;;;;;;;AAqBvC,SAAS,YAAY,IAAW;AAC9B,KAAI,CAAC,oBAAoB,GAAG,CAE1B;AAIF,aAAY;AAGZ,QAAO,QAAQ,KAAA;;;;;;;;;AAUjB,SAAS,aAAa,GAAkB;AACtC,KAAI,EAAE,QAAQ,UAAU;AACtB,IAAE,iBAAiB;AACnB,cAAY,EAAE;;;;AAKlB,SAAS,aAAa;AACpB,KAAI,MAAM,OAAO;AACf,eAAa,MAAM,MAAM;AACzB,QAAM,QAAQ,KAAA;;;;AAKlB,SAAS,cAAc,IAAwB;CAC7C,MAAM,UAAqB,EAAE;CAC7B,IAAI,SAAS,GAAG;AAChB,QAAO,QAAQ;AACb,UAAQ,KAAK,OAAO;AACpB,WAAS,OAAO;;AAElB,QAAO;;;AAIT,SAAS,oBAAoB,GAAmB;CAC9C,MAAM,SAAS,MAAM,OAAO,OAAO,UAAU;AAC7C,KAAI,aAAa,cAAc,EAAE,yBAAyB,WAAW,QAAQ;EAC3E,MAAM,uBAAuB,cAAc,EAAE,cAAc;AAC3D,SACE,EAAE,cAAc,OAAA,oBAChB,CAAC,qBAAqB,MAAM,WAAW,OAAO,OAAA,iBAAkB,IAChE,EAAE,kBAAkB;;AAGxB,QAAO;;;;;;;AAYT,SAAgB,WAAW,MAA4B;AACrD,2BAA0B;;;;CAK1B,SAAS,sBAAsB,IAAW;EACxC,MAAM,QAAQ,MAAM,KAAK,MAAM,IAAA;AAC/B,cAAY;AAGZ,MAAI,QAAQ,EACV,OAAM,QAAQ,iBAAiB,YAAY,GAAG,EAAE,MAAM;MAEtD,aAAY,GAAG;;;;;CAOnB,SAAS,YAAY,IAAW;AAC9B,cAAY;AAGZ,WAAS,iBAAiB,WAAW,cAAc;GAAE,MAAM;GAAM,SAAS;GAAM,CAAC;AAGjF,SAAO,QAAQ;;AAGjB,aACQ,MAAM,KAAK,UAAU,GAC1B,QAAQ,WAAW;AAClB,MAAI,QAAQ;AACV,UAAO,oBAAoB,cAAc,sBAAsB;AAC/D,UAAO,oBAAoB,cAAc,YAAY;AACrD,UAAO,oBAAoB,SAAS,YAAY;AAChD,UAAO,oBAAoB,QAAQ,YAAY;AAE/C,UAAO,gBAAgB,mBAAmB;;AAE5C,MAAI,QAAQ;AACV,UAAO,iBAAiB,cAAc,sBAAsB;AAC5D,UAAO,iBAAiB,cAAc,YAAY;AAClD,UAAO,iBAAiB,SAAS,YAAY;AAC7C,UAAO,iBAAiB,QAAQ,YAAY;AAE5C,UAAO,aAAa,oBAAoB,WAAW;;IAGvD,EAAE,WAAW,MAAM,CACpB;AAGD,sBAAqB;AACnB,cAAY;EAEZ,MAAM,SAAS,MAAM,KAAK,UAAU;AACpC,MAAI,QAAQ;AACV,UAAO,oBAAoB,cAAc,sBAAsB;AAC/D,UAAO,oBAAoB,cAAc,YAAY;AACrD,UAAO,oBAAoB,SAAS,YAAY;AAChD,UAAO,oBAAoB,QAAQ,YAAY;AAC/C,UAAO,gBAAgB,mBAAmB;;AAI5C,MAAI,MAAM,OAAO,OAAO,UAAU,KAAK,MAAM,KAAK,UAAU,CAC1D,QAAO,QAAQ,KAAA;GAEjB"}
package/dist/style.css CHANGED
@@ -440,7 +440,12 @@
440
440
  border-width: 1px;
441
441
  }
442
442
 
443
- :where(.scalar-app) input::placeholder {
443
+ :where(.scalar-app) input::placeholder, :where(.scalar-app) text-area::placeholder {
444
+ color: var(--scalar-color-3);
445
+ font-family: var(--scalar-font);
446
+ }
447
+
448
+ :where(.scalar-app) ::-webkit-input-placeholder {
444
449
  color: var(--scalar-color-3);
445
450
  font-family: var(--scalar-font);
446
451
  }
@@ -652,10 +657,18 @@
652
657
  inset-block: 2px;
653
658
  }
654
659
 
660
+ .scalar-app .-start {
661
+ inset-inline-start: -4px;
662
+ }
663
+
655
664
  .scalar-app .start {
656
665
  inset-inline-start: 4px;
657
666
  }
658
667
 
668
+ .scalar-app .-end {
669
+ inset-inline-end: -4px;
670
+ }
671
+
659
672
  .scalar-app .end {
660
673
  inset-inline-end: 4px;
661
674
  }
@@ -3590,7 +3603,7 @@ to {
3590
3603
  .hljs.language-objectivec .hljs-meta {
3591
3604
  color: var(--scalar-color-1);
3592
3605
  }
3593
- .hljs.language-objectivec .hljs-built_in, .hljs-built_in {
3606
+ .hljs.language-objectivec .hljs-built_in {
3594
3607
  color: var(--scalar-color-orange);
3595
3608
  }
3596
3609
  .scalar-code-block pre {
@@ -3852,9 +3865,6 @@ code.hljs {
3852
3865
  .hljs.language-objectivec .hljs-built_in {
3853
3866
  color: var(--scalar-color-orange);
3854
3867
  }
3855
- .hljs-built_in {
3856
- color: var(--scalar-color-orange);
3857
- }
3858
3868
  .scalar-app {
3859
3869
  /* Base container and variables */
3860
3870
  .markdown {
@@ -4555,7 +4565,7 @@ to {
4555
4565
  }
4556
4566
  :where(body) > .scalar-tooltip {
4557
4567
  --scalar-tooltip-padding: 8px;
4558
- padding: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
4568
+ padding: var(--scalar-tooltip-padding);
4559
4569
  z-index: 99999;
4560
4570
  max-width: 320px;
4561
4571
  font-size: var(--scalar-font-size-5);
@@ -4565,9 +4575,20 @@ to {
4565
4575
  overflow-wrap: break-word;
4566
4576
  color: var(--scalar-tooltip-color);
4567
4577
  }
4578
+ :where(body) > .scalar-tooltip[data-side="top"] {
4579
+ padding-bottom: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
4580
+ }
4581
+ :where(body) > .scalar-tooltip[data-side="bottom"] {
4582
+ padding-top: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
4583
+ }
4584
+ :where(body) > .scalar-tooltip[data-side="left"] {
4585
+ padding-right: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
4586
+ }
4587
+ :where(body) > .scalar-tooltip[data-side="right"] {
4588
+ padding-left: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
4589
+ }
4568
4590
  :where(body) > .scalar-tooltip:before {
4569
4591
  content: "";
4570
- inset: var(--scalar-tooltip-offset);
4571
4592
  z-index: calc(1 * -1);
4572
4593
  border-radius: var(--scalar-radius);
4573
4594
  background-color: var(--scalar-tooltip-background);
@@ -4575,6 +4596,19 @@ to {
4575
4596
  -webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
4576
4597
  backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
4577
4598
  position: absolute;
4599
+ inset: 0;
4600
+ }
4601
+ :where(body) > .scalar-tooltip[data-side="top"]:before {
4602
+ bottom: var(--scalar-tooltip-offset);
4603
+ }
4604
+ :where(body) > .scalar-tooltip[data-side="bottom"]:before {
4605
+ top: var(--scalar-tooltip-offset);
4606
+ }
4607
+ :where(body) > .scalar-tooltip[data-side="left"]:before {
4608
+ right: var(--scalar-tooltip-offset);
4609
+ }
4610
+ :where(body) > .scalar-tooltip[data-side="right"]:before {
4611
+ left: var(--scalar-tooltip-offset);
4578
4612
  }
4579
4613
  :where(body.dark-mode) > .scalar-tooltip:before {
4580
4614
  --tw-shadow: inset 0 0 0 var(--tw-shadow-color, var(--scalar-border-width)) var(--scalar-border-color);
@@ -195,7 +195,7 @@ to {
195
195
  .hljs.language-objectivec .hljs-meta {
196
196
  color: var(--scalar-color-1);
197
197
  }
198
- .hljs.language-objectivec .hljs-built_in, .hljs-built_in {
198
+ .hljs.language-objectivec .hljs-built_in {
199
199
  color: var(--scalar-color-orange);
200
200
  }
201
201
  .scalar-code-block pre {
@@ -457,9 +457,6 @@ code.hljs {
457
457
  .hljs.language-objectivec .hljs-built_in {
458
458
  color: var(--scalar-color-orange);
459
459
  }
460
- .hljs-built_in {
461
- color: var(--scalar-color-orange);
462
- }
463
460
  .scalar-app {
464
461
  /* Base container and variables */
465
462
  .markdown {
@@ -1160,7 +1157,7 @@ to {
1160
1157
  }
1161
1158
  :where(body) > .scalar-tooltip {
1162
1159
  --scalar-tooltip-padding: 8px;
1163
- padding: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
1160
+ padding: var(--scalar-tooltip-padding);
1164
1161
  z-index: 99999;
1165
1162
  max-width: 320px;
1166
1163
  font-size: var(--scalar-font-size-5);
@@ -1170,9 +1167,20 @@ to {
1170
1167
  overflow-wrap: break-word;
1171
1168
  color: var(--scalar-tooltip-color);
1172
1169
  }
1170
+ :where(body) > .scalar-tooltip[data-side="top"] {
1171
+ padding-bottom: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
1172
+ }
1173
+ :where(body) > .scalar-tooltip[data-side="bottom"] {
1174
+ padding-top: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
1175
+ }
1176
+ :where(body) > .scalar-tooltip[data-side="left"] {
1177
+ padding-right: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
1178
+ }
1179
+ :where(body) > .scalar-tooltip[data-side="right"] {
1180
+ padding-left: calc(var(--scalar-tooltip-padding) + var(--scalar-tooltip-offset));
1181
+ }
1173
1182
  :where(body) > .scalar-tooltip:before {
1174
1183
  content: "";
1175
- inset: var(--scalar-tooltip-offset);
1176
1184
  z-index: calc(1 * -1);
1177
1185
  border-radius: var(--scalar-radius);
1178
1186
  background-color: var(--scalar-tooltip-background);
@@ -1180,6 +1188,19 @@ to {
1180
1188
  -webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
1181
1189
  backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
1182
1190
  position: absolute;
1191
+ inset: 0;
1192
+ }
1193
+ :where(body) > .scalar-tooltip[data-side="top"]:before {
1194
+ bottom: var(--scalar-tooltip-offset);
1195
+ }
1196
+ :where(body) > .scalar-tooltip[data-side="bottom"]:before {
1197
+ top: var(--scalar-tooltip-offset);
1198
+ }
1199
+ :where(body) > .scalar-tooltip[data-side="left"]:before {
1200
+ right: var(--scalar-tooltip-offset);
1201
+ }
1202
+ :where(body) > .scalar-tooltip[data-side="right"]:before {
1203
+ left: var(--scalar-tooltip-offset);
1183
1204
  }
1184
1205
  :where(body.dark-mode) > .scalar-tooltip:before {
1185
1206
  --tw-shadow: inset 0 0 0 var(--tw-shadow-color, var(--scalar-border-width)) var(--scalar-border-color);
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "url": "git+https://github.com/scalar/scalar.git",
11
11
  "directory": "packages/components"
12
12
  },
13
- "version": "0.27.1",
13
+ "version": "0.27.3",
14
14
  "engines": {
15
15
  "node": ">=22"
16
16
  },
@@ -222,10 +222,10 @@
222
222
  "vue": "^3.5.30",
223
223
  "vue-component-type-helpers": "^3.2.6",
224
224
  "@scalar/helpers": "0.8.2",
225
- "@scalar/code-highlight": "0.3.5",
226
- "@scalar/use-hooks": "0.4.6",
227
- "@scalar/themes": "0.16.0",
228
- "@scalar/icons": "0.7.3"
225
+ "@scalar/code-highlight": "0.3.6",
226
+ "@scalar/icons": "0.7.3",
227
+ "@scalar/themes": "0.16.1",
228
+ "@scalar/use-hooks": "0.4.7"
229
229
  },
230
230
  "devDependencies": {
231
231
  "@playwright/test": "1.59.1",