Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@featherds/composables

Package Overview
Dependencies
Maintainers
2
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@featherds/composables - npm Package Compare versions

Comparing version 0.9.6 to 0.10.0

events/OutsideClick.d.ts

85

events/OutsideClick.js
import { watch, onBeforeUnmount, ref, onMounted } from "vue";
const useOutsideClick = (elementRef, listener) => {
const active = ref(false);
const windowBlurChecker = (e) => {
if (e.target === window) {
listener(e);
}
};
const outSideClick = (e) => {
if (!elementRef.value.contains(e.target)) {
listener(e);
}
};
const removeEvents = () => {
if (document && window) {
document.removeEventListener("click", outSideClick);
document.removeEventListener("focus", outSideClick, true);
window.removeEventListener("blur", windowBlurChecker);
}
};
onMounted(() => {
const unwatch = watch(
[elementRef, active],
([el, enabled]) => {
if (el && document && window && enabled) {
document.addEventListener("click", outSideClick);
document.addEventListener("focus", outSideClick, true);
window.addEventListener("blur", windowBlurChecker);
} else {
removeEvents();
const active = ref(false);
const windowBlurChecker = (e) => {
if (e.target === window) {
listener(e);
}
},
{
immediate: true,
}
);
onBeforeUnmount(() => {
unwatch();
removeEvents();
};
const outSideClick = (e) => {
let elementArr = [];
if (Array.isArray(elementRef.value)) {
elementArr = elementRef.value;
}
else {
elementArr = [elementRef.value];
}
const contained = elementArr.some((el) => el && el.contains(e.target));
if (!contained) {
listener(e);
}
};
const removeEvents = () => {
if (document && window) {
document.removeEventListener("click", outSideClick, true);
document.removeEventListener("focus", outSideClick, true);
window.removeEventListener("blur", windowBlurChecker);
}
};
onMounted(() => {
const unwatch = watch(active, (enabled) => {
if (document && window && enabled) {
document.addEventListener("click", outSideClick, true);
document.addEventListener("focus", outSideClick, true);
window.addEventListener("blur", windowBlurChecker);
}
else {
removeEvents();
}
}, {
immediate: true,
});
onBeforeUnmount(() => {
unwatch();
removeEvents();
});
});
});
return active;
return active;
};
export { useOutsideClick };
import { watch, onBeforeUnmount, ref, onMounted } from "vue";
const useResize = (listener) => {
const active = ref(false);
let ticking = false;
const resizeHandler = () => {
listener();
ticking = false;
};
function requestTick() {
if (!ticking) {
requestAnimationFrame(resizeHandler);
ticking = true;
const active = ref(false);
let ticking = false;
const resizeHandler = () => {
listener();
ticking = false;
};
function requestTick() {
if (!ticking) {
requestAnimationFrame(resizeHandler);
ticking = true;
}
}
}
const removeEvents = () => {
if (window) {
window.removeEventListener("resize", requestTick);
}
};
onMounted(() => {
const unwatch = watch(
active,
(enabled) => {
if (window && enabled) {
window.addEventListener("resize", requestTick);
} else {
removeEvents();
const removeEvents = () => {
if (window) {
window.removeEventListener("resize", requestTick);
}
},
{
immediate: true,
}
);
onBeforeUnmount(() => {
unwatch();
removeEvents();
};
onMounted(() => {
const unwatch = watch(active, (enabled) => {
if (window && enabled) {
window.addEventListener("resize", requestTick);
}
else {
removeEvents();
}
}, {
immediate: true,
});
onBeforeUnmount(() => {
unwatch();
removeEvents();
});
});
});
return active;
return active;
};
export { useResize };
import { watch, onBeforeUnmount, ref } from "vue";
const useScroll = (elementRef, listener) => {
const active = ref(false);
let ticking = false;
const scrollHandler = () => {
listener();
ticking = false;
};
function requestTick() {
if (!ticking) {
requestAnimationFrame(scrollHandler);
ticking = true;
const active = ref(false);
let ticking = false;
const scrollHandler = (e) => {
listener(e);
ticking = false;
};
function requestTick(e) {
if (!ticking) {
requestAnimationFrame(() => scrollHandler(e));
ticking = true;
}
}
}
const removeEvents = () => {
if (elementRef.value) {
elementRef.value.removeEventListener("scroll", requestTick);
}
};
const unwatch = watch(
[elementRef, active],
([el, enabled], previous) => {
if (previous && previous.length && previous[0]) {
previous[0].removeEventListener("scroll", requestTick);
}
if (enabled && el) {
el.addEventListener("scroll", requestTick, { passive: true });
} else {
const removeEvents = () => {
if (elementRef.value) {
elementRef.value.removeEventListener("scroll", requestTick, true);
}
};
const unwatch = watch([elementRef, active], ([el, enabled], previous) => {
if (previous && previous.length && previous[0]) {
previous[0].removeEventListener("scroll", requestTick, true);
}
if (enabled && el) {
el.addEventListener("scroll", requestTick, true);
}
else {
removeEvents();
}
}, {
immediate: true,
});
onBeforeUnmount(() => {
unwatch();
removeEvents();
}
},
{
immediate: true,
}
);
onBeforeUnmount(() => {
unwatch();
removeEvents();
});
return active;
});
return active;
};
export { useScroll };

@@ -1,8 +0,6 @@

import { Ref, ComputedRef } from "vue";
declare module "@featherds/composables/events/Scroll" {
import { Ref } from "vue";
const useScroll: (
ref: Ref<HTMLElement>,
callback: () => void,
threshold: number
ref: Ref<HTMLElement | Document>,
callback: () => void
) => Ref<boolean>;

@@ -13,6 +11,4 @@ export { useScroll };

declare module "@featherds/composables/events/Resize" {
const useResize: (
callback: () => void,
threshold: number
) => Ref<boolean>;
import { Ref } from "vue";
const useResize: (callback: () => void) => Ref<boolean>;
export { useResize };

@@ -22,2 +18,3 @@ }

declare module "@featherds/composables/events/OutsideClick" {
import { Ref } from "vue";
const useOutsideClick: (

@@ -32,7 +29,11 @@ ref: Ref<HTMLElement>,

declare module "@featherds/composables/LabelProperty" {
const useLabelProperty: (
label: Ref<Record<string, string>>,
defaults: Record<string, string>
) => ComputedRef<string>[];
import { Ref, ComputedRef } from "vue";
type Labels<Type> = {
[Property in keyof Type as `${string & Property}Label`]: ComputedRef<
Type[Property]
>;
};
const useLabelProperty: <T>(label: Ref<Partial<T>>, defaults: T) => Labels<T>;
export { useLabelProperty };

@@ -42,2 +43,3 @@ }

declare module "@featherds/composables/modal/CloseOnEsc" {
import { Ref } from "vue";
const useCloseOnEsc: (ref: Ref<boolean>) => Ref<boolean>;

@@ -48,2 +50,3 @@ export { useCloseOnEsc };

declare module "@featherds/composables/modal/HideOverflow" {
import { Ref } from "vue";
const useHideBodyOverflow: (ref: Ref<boolean>) => void;

@@ -58,4 +61,5 @@ const useHideRelativeOverflow: (

declare module "@featherds/composables/modal/RestoreFocus" {
import { Ref } from "vue";
const useRestoreFocus: (ref: Ref<boolean>) => void;
export { useRestoreFocus };
}
import { computed } from "vue";
const useLabelProperty = (labelRef, defaultLabels) => {
const result = {};
Object.keys(defaultLabels).forEach((key) => {
result[`${key}Label`] = computed(() => {
return labelRef.value[key] ? labelRef.value[key] : defaultLabels[key];
const result = {};
Object.keys(defaultLabels).forEach((key) => {
result[`${key}Label`] = computed(() => {
return labelRef.value[key] ? labelRef.value[key] : defaultLabels[key];
});
});
});
return result;
return result;
};
export { useLabelProperty };
import { watch, ref, onBeforeUnmount } from "vue";
import { KEYCODES } from "@featherds/utils/keys";
const useCloseOnEsc = (visibleRef) => {
const result = ref(false);
const handleEsc = (e) => {
if (e.keyCode === KEYCODES.ESCAPE) {
e.preventDefault();
result.value = !result.value;
}
};
watch(
visibleRef,
(v) => {
if (v) {
document.addEventListener("keydown", handleEsc);
} else if (typeof document !== "undefined") {
const result = ref(false);
const handleEsc = (e) => {
if (e.keyCode === KEYCODES.ESCAPE) {
e.preventDefault();
result.value = !result.value;
}
};
watch(visibleRef, (v) => {
if (v) {
document.addEventListener("keydown", handleEsc);
}
else if (typeof document !== "undefined") {
document.removeEventListener("keydown", handleEsc);
}
}, { immediate: true });
onBeforeUnmount(() => {
document.removeEventListener("keydown", handleEsc);
}
},
{ immediate: true }
);
onBeforeUnmount(() => {
document.removeEventListener("keydown", handleEsc);
});
return result;
});
return result;
};
export { useCloseOnEsc };
import { watch, onBeforeUnmount, nextTick, onMounted } from "vue";
const hideBodyOverflow = (e) => {
const originalOverflow = e.style.overflow;
e.style.overflow = "hidden";
return originalOverflow;
if (e === false) {
return "hidden";
}
const originalOverflow = e.style.overflow;
e.style.overflow = "hidden";
return originalOverflow;
};
const resetBodyOverflow = (originalOverflow, element) => {
if (originalOverflow !== undefined && element) {
element.style.overflow = originalOverflow;
}
return undefined;
if (originalOverflow !== undefined && element !== false) {
element.style.overflow = originalOverflow;
}
return undefined;
};
const useHideBodyOverflow = (visibleRef) => {
let originalOverflow;
const element =
typeof document !== "undefined"
? document.body
: { style: { overflow: "hidden" } };
onBeforeUnmount(() => resetBodyOverflow(originalOverflow, element));
onMounted(() =>
watch(
visibleRef,
(v) => {
let originalOverflow;
const element = typeof document !== "undefined" ? document.body : false;
onBeforeUnmount(() => resetBodyOverflow(originalOverflow, element));
onMounted(() => watch(visibleRef, (v) => {
if (v) {
nextTick(() => {
originalOverflow = hideBodyOverflow(element);
});
} else {
//hidden
resetBodyOverflow(originalOverflow, element);
nextTick(() => {
originalOverflow = hideBodyOverflow(element);
});
}
},
{ immediate: true }
)
);
else {
//hidden
resetBodyOverflow(originalOverflow, element);
}
}, { immediate: true }));
};
const useHideRelativeOverflow = (visibleRef, elementRef) => {
let originalOverflow;
onBeforeUnmount(() =>
resetBodyOverflow(
originalOverflow,
elementRef.value ? elementRef.value.offsetParent : undefined
)
);
watch(
[visibleRef, elementRef],
([v, e]) => {
if (v && e) {
nextTick(() => {
originalOverflow = hideBodyOverflow(e.offsetParent);
});
} else if (e) {
//hidden
resetBodyOverflow(originalOverflow, e.offsetParent);
}
},
{
immediate: true,
}
);
let originalOverflow;
onBeforeUnmount(() => resetBodyOverflow(originalOverflow, elementRef.value ? elementRef.value.offsetParent : false));
watch([visibleRef, elementRef], ([v, e]) => {
if (v && e) {
nextTick(() => {
originalOverflow = hideBodyOverflow(e.offsetParent);
});
}
else if (e) {
//hidden
resetBodyOverflow(originalOverflow, e.offsetParent);
}
}, {
immediate: true,
});
};
export { useHideBodyOverflow, useHideRelativeOverflow };
import { watch } from "vue";
/**
* When visible is set to false it will try focus the triggering element.
* @param {Ref<Boolean>} visibleRef
*/
const useRestoreFocus = (visibleRef) => {
let focusAfterClosed;
watch(visibleRef, (v) => {
if (v) {
focusAfterClosed = document.activeElement;
} else {
//hidden
setTimeout(() => {
if (focusAfterClosed && focusAfterClosed.focus) {
focusAfterClosed.focus();
let focusAfterClosed;
watch(visibleRef, (v) => {
if (v) {
focusAfterClosed = document.activeElement;
}
focusAfterClosed = undefined;
}, 0);
}
});
else {
//hidden
setTimeout(() => {
if (focusAfterClosed && focusAfterClosed.focus) {
focusAfterClosed.focus();
}
focusAfterClosed = undefined;
}, 0);
}
});
};
export { useRestoreFocus };
{
"name": "@featherds/composables",
"version": "0.9.6",
"version": "0.10.0",
"publishConfig": {

@@ -8,5 +8,7 @@ "access": "public"

"author": "NantHealth",
"scripts": {},
"scripts": {
"compile": "tsc --declaration"
},
"dependencies": {
"@featherds/utils": "^0.9.6",
"@featherds/utils": "^0.10.0",
"vue": "^3.1.0-0"

@@ -18,4 +20,3 @@ },

],
"types": "./index.d.ts",
"gitHead": "04a74207e8bfa8d39acc470365e30dd6c90b2e8e"
"gitHead": "9871b17eaedcfc90174b78b21acb0cc06afd594c"
}

@@ -1,126 +0,113 @@

import { ref, watch, watchEffect, computed, provide } from "vue";
import { ref, watch, watchEffect, computed, provide, onBeforeUnmount, } from "vue";
import { useSelection } from "./Selection";
import { useValidation } from "@featherds/input-helper";
import { useSelection } from "./Selection";
import { getSafeId } from "@featherds/utils/id";
const useRadioGroup = (modelValue, emit, label, schema, errorFromInput) => {
const radios = ref([]);
const currentSelected = ref();
const firstElement = ref();
const firstElementId = ref();
watchEffect(() => {
if (!radios.value.length) {
return;
}
const values = radios.value.map((x) => x.value);
//select the radio that matches the current value
if (modelValue.value !== undefined && modelValue.value !== null) {
currentSelected.value = radios.value[values.indexOf(modelValue.value)];
}
//if nothing is selected then set the first property on first radio that isnt disabled
if (!currentSelected.value && radios.value.length) {
let enabled = radios.value.filter((x) => !x.disabled);
enabled = enabled.length ? enabled : radios.value; //if there is none enabled just use radios.
firstElement.value = enabled[0];
firstElement.value.first = true;
}
});
watch(currentSelected, (nv, ov) => {
if (ov) {
ov.checked = false;
}
if (nv) {
nv.checked = true;
}
});
const select = (radio) => {
if (radio && radio.disabled) {
return;
}
//reset first as we are now selecting and element
if (firstElement.value) {
firstElement.value.first = false;
}
if (currentSelected.value === radio) {
return;
}
emit("update:modelValue", radio.value);
currentSelected.value = radio;
radio.focus();
};
const currentHighlight = computed(() => {
return currentSelected.value || firstElement.value;
});
const selection = useSelection(currentHighlight, radios, select);
const groupId = computed(() => {
return getSafeId("feather-radio-group");
});
firstElementId.value = groupId.value;
let validate = useValidation(
firstElementId,
modelValue,
label,
schema,
errorFromInput
);
const register = (radio) => {
radios.value = [...radios.value, radio];
//lets try and instance validation
if (firstElementId.value === groupId.value) {
firstElementId.value = radio.id;
}
};
provide("register", register);
provide("select", select);
provide("blur", (e) => {
emit("blur", e);
});
const focus = () => {
if (currentSelected.value) {
currentSelected.value.focus();
}
};
const keydown = (e) => {
switch (e.keyCode) {
case 13:
case 32:
const radios = ref([]);
const currentSelected = ref();
const firstElement = ref();
const firstElementId = ref();
watchEffect(() => {
if (!radios.value.length) {
return;
}
const values = radios.value.map((x) => x.value);
//select the radio that matches the current value
if (modelValue.value !== undefined && modelValue.value !== null) {
currentSelected.value = radios.value[values.indexOf(modelValue.value)];
}
//if nothing is selected then set the first property on first radio that isnt disabled
if (!currentSelected.value && radios.value.length) {
let enabled = radios.value.filter((x) => !x.disabled);
enabled = enabled.length ? enabled : radios.value; //if there is none enabled just use radios.
firstElement.value = enabled[0];
firstElement.value.first = true;
}
});
watch(currentSelected, (nv, ov) => {
if (ov) {
ov.checked = false;
}
if (nv) {
nv.checked = true;
}
});
const select = (radio) => {
if (radio && radio.disabled) {
return;
}
//reset first as we are now selecting and element
if (firstElement.value) {
firstElement.value.first = false;
}
if (currentSelected.value === radio) {
return;
}
emit("update:modelValue", radio.value);
currentSelected.value = radio;
radio.focus();
};
const currentHighlight = computed(() => {
return currentSelected.value || firstElement.value;
});
const selection = useSelection(currentHighlight, radios, select);
const groupId = computed(() => {
return getSafeId("feather-radio-group");
});
firstElementId.value = groupId.value;
onBeforeUnmount(() => {
removeValidation();
});
const { validate, removeValidation } = useValidation(firstElementId, modelValue, label, schema, errorFromInput);
const register = (radio) => {
radios.value = [...radios.value, radio];
//lets try and instance validation
if (firstElementId.value === groupId.value) {
firstElementId.value = radio.id;
}
};
provide("register", register);
provide("select", select);
provide("blur", (e) => {
emit("blur", e);
});
const focus = () => {
if (currentSelected.value) {
select(currentSelected.value);
} else if (firstElement.value) {
select(firstElement.value);
currentSelected.value.focus();
}
break;
//next
case 40:
case 39:
selection.selectNext();
break;
//previous
case 37:
case 38:
selection.selectPrevious();
break;
default:
break;
}
};
return {
keydown,
...selection,
focus,
validate,
firstElementId,
groupId,
};
};
const keydown = (e) => {
switch (e.keyCode) {
case 13:
case 32:
if (currentSelected.value) {
select(currentSelected.value);
}
else if (firstElement.value) {
select(firstElement.value);
}
break;
//next
case 40:
case 39:
selection.selectNext();
break;
//previous
case 37:
case 38:
selection.selectPrevious();
break;
default:
break;
}
};
return {
keydown,
...selection,
focus,
validate,
firstElementId,
groupId,
};
};
export { useRadioGroup };
import { computed } from "vue";
const useSelection = (current, radios, select) => {
const notDisabled = computed(() => {
return radios.value.filter((x) => !x.disabled);
});
const index = computed(() => notDisabled.value.indexOf(current.value));
return {
selectPrevious() {
if (current.value && current.value.disabled) {
return;
}
if (index.value === 0) {
select(notDisabled.value[notDisabled.value.length - 1]);
} else {
select(notDisabled.value[index.value - 1]);
}
},
selectNext() {
if (current.value && current.value.disabled) {
return;
}
if (index.value === notDisabled.value.length - 1) {
select(notDisabled.value[0]);
} else {
select(notDisabled.value[index.value + 1]);
}
},
};
const notDisabled = computed(() => {
return radios.value.filter((x) => !x.disabled);
});
const index = computed(() => current.value ? notDisabled.value.indexOf(current.value) : -1);
return {
selectPrevious() {
if (current.value && current.value.disabled) {
return;
}
if (index.value === 0) {
select(notDisabled.value[notDisabled.value.length - 1]);
}
else {
select(notDisabled.value[index.value - 1]);
}
},
selectNext() {
if (current.value && current.value.disabled) {
return;
}
if (index.value === notDisabled.value.length - 1) {
select(notDisabled.value[0]);
}
else {
select(notDisabled.value[index.value + 1]);
}
},
};
};
export { useSelection };
import { ref, inject, computed, onMounted } from "vue";
const stockProps = {
id: {
type: String,
},
controls: {
type: String,
},
disabled: {
type: Boolean,
default: false,
},
id: {
type: String,
},
controls: {
type: String,
},
disabled: {
type: Boolean,
default: false,
},
};
const useTab = (props) => {
const selected = ref(false);
const tab = ref();
const _controls = ref(props.controls);
const _id = ref(props.id);
const focus = () => {
tab.value.focus();
};
const register = inject("registerTab");
let thisEl, parent, childNodes, index;
onMounted(() => {
thisEl = tab.value.parentElement;
parent = thisEl && thisEl.parentNode ? thisEl.parentNode : [];
childNodes = [].filter.call(parent.children, function (el) {
return el.querySelectorAll("[role=tab]").length;
const selected = ref(false);
const tab = ref();
const _controls = ref(props.controls);
const _id = ref(props.id);
const focus = () => {
if (tab.value) {
tab.value.focus();
}
};
const register = inject("registerTab");
onMounted(() => {
if (tab.value && register) {
const thisEl = tab.value.parentElement;
const parent = thisEl && thisEl.parentElement ? thisEl.parentElement : undefined;
const childNodes = Array.from(parent ? parent.children : []).filter((el) => el.querySelectorAll("[role=tab]").length);
const index = thisEl ? childNodes.indexOf(thisEl) : -1;
register({
el: tab.value,
focus,
disabled: props.disabled,
selected,
id: _id,
controls: _controls,
index: index,
});
}
});
index = thisEl ? [].indexOf.call(childNodes, thisEl) : null;
register({
el: tab.value,
focus,
disabled: props.disabled,
selected,
id: _id,
controls: _controls,
index: index,
const attrs = computed(() => {
return {
role: "tab",
ref: "tab",
tabindex: selected.value ? 0 : -1,
id: _id.value,
"aria-selected": selected.value ? "true" : "false",
"aria-controls": _controls.value,
"aria-disabled": props.disabled ? "true" : "false",
"data-ref-id": "feather-tab",
};
});
});
const attrs = computed(() => {
return {
role: "tab",
ref: "tab",
tabindex: selected.value ? 0 : -1,
id: _id.value,
"aria-selected": selected.value ? "true" : "false",
"aria-controls": _controls.value,
"aria-disabled": props.disabled ? "true" : "false",
"data-ref-id": "feather-tab",
selected,
attrs,
tab,
};
});
return {
selected,
attrs,
tab,
};
};
export { useTab, stockProps };

@@ -1,170 +0,158 @@

import { ref, toRef, watch, provide } from "vue";
import { ref, toRef, watch, provide, } from "vue";
import { getSafeId } from "@featherds/utils/id";
import { KEYCODES } from "@featherds/utils/keys";
const model = {
prop: "modelValue",
event: "update:modelValue",
prop: "modelValue",
event: "update:modelValue",
};
const emits = ["update:modelValue"];
const stockProps = {
modelValue: {
type: Number,
default: 0,
},
vertical: {
type: Boolean,
default: true,
},
modelValue: {
type: Number,
default: 0,
},
vertical: {
type: Boolean,
default: true,
},
};
const useTabContainer = (props, context) => {
const value = toRef(props, "modelValue");
const localSelected = ref(props.modelValue);
const pairs = ref([]);
watch(value, (v) => {
activateIndex(v);
});
const handleClick = (evt) => {
evt.preventDefault();
pairs.value.some((pair, i) => {
if (pair.tab.el.contains(evt.target)) {
selectIndex(i);
activateIndex(i);
return true;
}
return false;
const value = toRef(props, "modelValue");
const localSelected = ref(props.modelValue);
const pairs = ref([]);
watch(value, (v) => {
activateIndex(v);
});
};
const handleKey = (evt) => {
const isModifiedKeyPress = (e) => {
return e.shiftKey || e.ctrlKey || e.metaKey || e.altKey;
const handleClick = (evt) => {
evt.preventDefault();
pairs.value.some((pair, i) => {
if (pair.tab && pair.tab.el.contains(evt.target)) {
selectIndex(i);
activateIndex(i);
return true;
}
return false;
});
};
if (isModifiedKeyPress(evt)) {
return;
}
const key = evt.keyCode;
const stop = (e) => {
e.stopPropagation();
e.preventDefault();
const handleKey = (evt) => {
const isModifiedKeyPress = (e) => {
return e.shiftKey || e.ctrlKey || e.metaKey || e.altKey;
};
if (isModifiedKeyPress(evt)) {
return;
}
const key = evt.keyCode;
const stop = (e) => {
e.stopPropagation();
e.preventDefault();
};
const notDisabledPairs = pairs.value.filter((pair) => pair.tab && !pair.tab.disabled);
const focusedIndex = pairs.value.findIndex((pair) => pair.tab && pair.tab.el.contains(document.activeElement));
let index = focusedIndex !== -1 ? focusedIndex : localSelected.value;
const nextKeys = [KEYCODES.RIGHT];
const prevKeys = [KEYCODES.LEFT];
const selectKeys = [KEYCODES.ENTER, KEYCODES.SPACE];
if (props.vertical) {
nextKeys.push(KEYCODES.DOWN);
prevKeys.push(KEYCODES.UP);
}
if (nextKeys.indexOf(key) > -1) {
index++;
if (index >= notDisabledPairs.length) {
index = 0;
}
stop(evt);
selectIndex(pairs.value.indexOf(notDisabledPairs[index]));
}
else if (prevKeys.indexOf(key) > -1) {
index--;
if (index < 0) {
index = notDisabledPairs.length - 1;
}
stop(evt);
selectIndex(pairs.value.indexOf(notDisabledPairs[index]));
}
if (selectKeys.indexOf(key) > -1) {
activateIndex(index);
}
};
const notDisabledPairs = pairs.value.filter((pair) => !pair.tab.disabled);
const focusedIndex = pairs.value.findIndex((pair) =>
pair.tab.el.contains(document.activeElement)
);
let index = focusedIndex !== -1 ? focusedIndex : localSelected.value;
const nextKeys = [KEYCODES.RIGHT];
const prevKeys = [KEYCODES.LEFT];
const selectKeys = [KEYCODES.ENTER, KEYCODES.SPACE];
if (props.vertical) {
nextKeys.push(KEYCODES.DOWN);
prevKeys.push(KEYCODES.UP);
}
if (nextKeys.indexOf(key) > -1) {
index++;
if (index >= notDisabledPairs.length) {
index = 0;
}
stop(evt);
selectIndex(pairs.value.indexOf(notDisabledPairs[index]));
} else if (prevKeys.indexOf(key) > -1) {
index--;
if (index < 0) {
index = notDisabledPairs.length - 1;
}
stop(evt);
selectIndex(pairs.value.indexOf(notDisabledPairs[index]));
}
if (selectKeys.indexOf(key) > -1) {
activateIndex(index);
}
};
const selectIndex = (index) => {
pairs.value.forEach(function (pair, i) {
if (index === i) {
pair.tab.focus();
}
});
};
const activateIndex = (index) => {
const selected = pairs.value[index];
//couldnt find selected or tab is disabled
if (!selected || selected.tab.disabled) {
return;
}
pairs.value.forEach((pair, i) => {
pair.tab.selected = index === i;
if (pair.panel) {
pair.panel.selected = index === i;
}
});
localSelected.value = index;
context.emit("update:modelValue", index);
};
const registerTab = (tabVM) => {
const index = tabVM.index;
if (index > -1) {
pairs.value[index] = { ...pairs.value[index], tab: tabVM };
pairs.value = [...pairs.value];
linkIds();
}
};
provide("registerTab", registerTab);
const registerPanel = (tabPanelVM) => {
const index = tabPanelVM.index;
if (index > -1) {
pairs.value[index] = { ...pairs.value[index], panel: tabPanelVM };
pairs.value = [...pairs.value];
linkIds();
}
};
provide("registerPanel", registerPanel);
const linkIds = () => {
pairs.value.forEach(({ tab, panel }, index) => {
if (panel && tab) {
const tabId = tab.id || getSafeId("tab");
const panelId = tab.controls || getSafeId("panel");
tab.controls = panelId;
tab.id = tabId;
panel.tab = tabId;
panel.id = panelId;
}
if (index === localSelected.value) {
if (panel) {
panel.selected = true;
const selectIndex = (index) => {
pairs.value.forEach(function (pair, i) {
if (index === i && pair.tab) {
pair.tab.focus();
}
});
};
const activateIndex = (index) => {
const selected = pairs.value[index];
//couldnt find selected or tab is disabled
if (!selected || (selected.tab && selected.tab.disabled)) {
return;
}
if (tab) {
tab.selected = true;
pairs.value.forEach((pair, i) => {
if (pair.tab) {
pair.tab.selected = index === i;
}
if (pair.panel) {
pair.panel.selected = index === i;
}
});
localSelected.value = index;
context.emit("update:modelValue", index);
};
const registerTab = (tabVM) => {
const index = tabVM.index;
if (index > -1) {
pairs.value[index] = { ...pairs.value[index], tab: tabVM };
pairs.value = [...pairs.value];
linkIds();
}
}
});
};
const listeners = {
click: handleClick,
keydown: handleKey,
};
const attrs = {
role: "tablist",
};
return {
listeners,
attrs,
selected: localSelected,
pairs, //feather tab container watches this
};
};
provide("registerTab", registerTab);
const registerPanel = (tabPanelVM) => {
const index = tabPanelVM.index;
if (index > -1) {
pairs.value[index] = {
...pairs.value[index],
panel: tabPanelVM,
};
pairs.value = [...pairs.value];
linkIds();
}
};
provide("registerPanel", registerPanel);
const linkIds = () => {
pairs.value.forEach(({ tab, panel }, index) => {
if (panel && tab) {
const tabId = tab.id || getSafeId("tab");
const panelId = tab.controls || getSafeId("panel");
tab.controls = panelId;
tab.id = tabId;
panel.tab = tabId;
panel.id = panelId;
}
if (index === localSelected.value) {
if (panel) {
panel.selected = true;
}
if (tab) {
tab.selected = true;
}
}
});
};
const listeners = {
click: handleClick,
keydown: handleKey,
};
const attrs = {
role: "tablist",
};
return {
listeners,
attrs,
selected: localSelected,
pairs, //feather tab container watches this
};
};
export { useTabContainer, stockProps, model, emits };
import { ref, inject, computed, onMounted } from "vue";
const stockProps = {
id: {
type: String,
},
tab: {
type: String,
},
id: {
type: String,
},
tab: {
type: String,
},
};
const useTabPanel = (props) => {
const selected = ref(false);
const panel = ref();
const _tab = ref(props.tab);
const _id = ref(props.id);
const register = inject("registerPanel");
let thisEl, parent, index;
onMounted(() => {
thisEl = panel.value;
parent = thisEl && thisEl.parentNode ? thisEl.parentNode : [];
index = thisEl
? Array.prototype.indexOf.call(parent.children, thisEl)
: null;
register({
selected,
id: _id,
tab: _tab,
el: panel.value,
index: index,
const selected = ref(false);
const panel = ref();
const _tab = ref(props.tab);
const _id = ref(props.id);
const register = inject("registerPanel");
onMounted(() => {
if (register) {
const thisEl = panel.value;
const parent = thisEl && thisEl.parentElement ? thisEl.parentElement : undefined;
const index = thisEl
? Array.from(parent ? parent.children : []).indexOf(thisEl)
: -1;
register({
selected,
id: _id,
tab: _tab,
el: panel.value,
index: index,
});
}
});
});
const attrs = computed(() => {
const attrs = computed(() => {
return {
role: "tabpanel",
id: _id.value,
ref: "panel",
tabindex: "0",
"aria-expanded": selected.value ? "true" : "false",
"aria-labelledby": _tab.value,
"data-ref-id": "feather-tab-panel",
};
});
return {
role: "tabpanel",
id: _id.value,
ref: "panel",
tabindex: "0",
"aria-expanded": selected.value ? "true" : "false",
"aria-labelledby": _tab.value,
"data-ref-id": "feather-tab-panel",
selected,
attrs,
panel,
};
});
return {
selected,
attrs,
panel,
};
};
export { useTabPanel, stockProps };
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc