Private
Public Access
1
0

feat: Fluent UI Outlook Lite + connections mockup

This commit is contained in:
2026-04-14 18:52:25 +00:00
parent 1199eff6c3
commit dfa4010406
34820 changed files with 1003813 additions and 205 deletions

View File

@@ -0,0 +1,2 @@
export const DATA_OVERFLOWING = 'data-overflowing';
export const DATA_OVERFLOW_GROUP = 'data-overflow-group';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/consts.ts"],"sourcesContent":["export const DATA_OVERFLOWING = 'data-overflowing';\nexport const DATA_OVERFLOW_GROUP = 'data-overflow-group';\n"],"names":["DATA_OVERFLOWING","DATA_OVERFLOW_GROUP"],"mappings":"AAAA,OAAO,MAAMA,mBAAmB,mBAAmB;AACnD,OAAO,MAAMC,sBAAsB,sBAAsB"}

View File

@@ -0,0 +1,22 @@
/**
* Helper function that creates a resize observer in the element's own window global
* @param elementToObserve - Uses the element's window global to create the resize observer
* @param callback
* @returns function to cleanup the resize observer
*/ export function observeResize(elementToObserve, callback) {
var _elementToObserve_ownerDocument_defaultView;
const GlobalResizeObserver = (_elementToObserve_ownerDocument_defaultView = elementToObserve.ownerDocument.defaultView) === null || _elementToObserve_ownerDocument_defaultView === void 0 ? void 0 : _elementToObserve_ownerDocument_defaultView.ResizeObserver;
if (!GlobalResizeObserver) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error('@fluentui/priority-overflow', 'ResizeObserver does not exist on container window');
}
return ()=>null;
}
let resizeObserver = new GlobalResizeObserver(callback);
resizeObserver.observe(elementToObserve);
return ()=>{
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
resizeObserver = undefined;
};
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/createResizeObserver.ts"],"sourcesContent":["/**\n * Helper function that creates a resize observer in the element's own window global\n * @param elementToObserve - Uses the element's window global to create the resize observer\n * @param callback\n * @returns function to cleanup the resize observer\n */\nexport function observeResize(elementToObserve: HTMLElement, callback: ResizeObserverCallback): () => void {\n const GlobalResizeObserver = elementToObserve.ownerDocument.defaultView?.ResizeObserver;\n\n if (!GlobalResizeObserver) {\n if (process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.error('@fluentui/priority-overflow', 'ResizeObserver does not exist on container window');\n }\n return () => null;\n }\n\n let resizeObserver: InstanceType<typeof GlobalResizeObserver> | undefined = new GlobalResizeObserver(callback);\n resizeObserver.observe(elementToObserve);\n\n return () => {\n resizeObserver?.disconnect();\n resizeObserver = undefined;\n };\n}\n"],"names":["observeResize","elementToObserve","callback","GlobalResizeObserver","ownerDocument","defaultView","ResizeObserver","process","env","NODE_ENV","console","error","resizeObserver","observe","disconnect","undefined"],"mappings":"AAAA;;;;;CAKC,GACD,OAAO,SAASA,cAAcC,gBAA6B,EAAEC,QAAgC;QAC9DD;IAA7B,MAAME,wBAAuBF,8CAAAA,iBAAiBG,aAAa,CAACC,WAAW,cAA1CJ,kEAAAA,4CAA4CK,cAAc;IAEvF,IAAI,CAACH,sBAAsB;QACzB,IAAII,QAAQC,GAAG,CAACC,QAAQ,KAAK,cAAc;YACzC,sCAAsC;YACtCC,QAAQC,KAAK,CAAC,+BAA+B;QAC/C;QACA,OAAO,IAAM;IACf;IAEA,IAAIC,iBAAwE,IAAIT,qBAAqBD;IACrGU,eAAeC,OAAO,CAACZ;IAEvB,OAAO;QACLW,2BAAAA,qCAAAA,eAAgBE,UAAU;QAC1BF,iBAAiBG;IACnB;AACF"}

View File

@@ -0,0 +1,24 @@
/**
* Microtask debouncer
* https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide
* @param fn - Function to debounce
* @returns debounced function
*/ export function debounce(fn) {
let pending;
// React testing platforms will often output errors when state updates happen outside `act`
// Since there is nothing obvious to wait for we just avoid debouncing in unit test environments
if (process.env.NODE_ENV === 'test') {
return fn;
}
return ()=>{
if (!pending) {
pending = true;
queueMicrotask(()=>{
// Need to set pending to `false` before the debounced function is run.
// React can actually interrupt the function while it's running!
pending = false;
fn();
});
}
};
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/debounce.ts"],"sourcesContent":["/**\n * Microtask debouncer\n * https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n * @param fn - Function to debounce\n * @returns debounced function\n */\nexport function debounce(fn: Function): () => void {\n let pending: boolean;\n\n // React testing platforms will often output errors when state updates happen outside `act`\n // Since there is nothing obvious to wait for we just avoid debouncing in unit test environments\n if (process.env.NODE_ENV === 'test') {\n return fn as () => void;\n }\n\n return () => {\n if (!pending) {\n pending = true;\n queueMicrotask(() => {\n // Need to set pending to `false` before the debounced function is run.\n // React can actually interrupt the function while it's running!\n pending = false;\n fn();\n });\n }\n };\n}\n"],"names":["debounce","fn","pending","process","env","NODE_ENV","queueMicrotask"],"mappings":"AAAA;;;;;CAKC,GACD,OAAO,SAASA,SAASC,EAAY;IACnC,IAAIC;IAEJ,2FAA2F;IAC3F,gGAAgG;IAChG,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,QAAQ;QACnC,OAAOJ;IACT;IAEA,OAAO;QACL,IAAI,CAACC,SAAS;YACZA,UAAU;YACVI,eAAe;gBACb,uEAAuE;gBACvE,gEAAgE;gBAChEJ,UAAU;gBACVD;YACF;QACF;IACF;AACF"}

View File

@@ -0,0 +1 @@
export { createOverflowManager } from './overflowManager';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { createOverflowManager } from './overflowManager';\nexport type {\n ObserveOptions,\n OnUpdateItemVisibility,\n OnUpdateItemVisibilityPayload,\n OnUpdateOverflow,\n OverflowAxis,\n OverflowDirection,\n OverflowEventPayload,\n OverflowGroupState,\n OverflowItemEntry,\n OverflowDividerEntry,\n OverflowManager,\n} from './types';\n"],"names":["createOverflowManager"],"mappings":"AAAA,SAASA,qBAAqB,QAAQ,oBAAoB"}

View File

@@ -0,0 +1,302 @@
import { DATA_OVERFLOWING, DATA_OVERFLOW_GROUP } from './consts';
import { observeResize } from './createResizeObserver';
import { debounce } from './debounce';
import { createPriorityQueue } from './priorityQueue';
/**
* @internal
* @returns overflow manager instance
*/ export function createOverflowManager() {
// calls to `offsetWidth or offsetHeight` can happen multiple times in an update
// Use a cache to avoid causing too many recalcs and avoid scripting time to meausure sizes
const sizeCache = new Map();
let container;
let overflowMenu;
// Set as true when resize observer is observing
let observing = false;
// If true, next update will dispatch to onUpdateOverflow even if queue top states don't change
// Initially true to force dispatch on first mount
let forceDispatch = true;
const options = {
padding: 10,
overflowAxis: 'horizontal',
overflowDirection: 'end',
minimumVisible: 0,
onUpdateItemVisibility: ()=>undefined,
onUpdateOverflow: ()=>undefined,
hasHiddenItems: false
};
const overflowItems = {};
const overflowDividers = {};
let disposeResizeObserver = ()=>null;
const getNextItem = (queueToDequeue, queueToEnqueue)=>{
const nextItem = queueToDequeue.dequeue();
queueToEnqueue.enqueue(nextItem);
return overflowItems[nextItem];
};
const groupManager = createGroupManager();
function compareItems(lt, rt) {
if (!lt || !rt) {
return 0;
}
const lte = overflowItems[lt];
const rte = overflowItems[rt];
// TODO this should not happen but there have been reports of one of these items being undefined
// Try to find a consistent repro for this
if (!lte || !rte) {
return lte ? 1 : -1;
}
// Pinned items have "infinite" priority - they should never be hidden
if (lte.pinned !== rte.pinned) {
return lte.pinned ? 1 : -1;
}
if (lte.priority !== rte.priority) {
return lte.priority > rte.priority ? 1 : -1;
}
// Node.DOCUMENT_POSITION_FOLLOWING = 4, Node.DOCUMENT_POSITION_PRECEDING = 2
const positionStatusBit = options.overflowDirection === 'end' ? 4 : 2;
// eslint-disable-next-line no-bitwise
return lte.element.compareDocumentPosition(rte.element) & positionStatusBit ? 1 : -1;
}
function getElementAxisSize(horizontal, vertical, el) {
if (!sizeCache.has(el)) {
sizeCache.set(el, options.overflowAxis === 'horizontal' ? el[horizontal] : el[vertical]);
}
return sizeCache.get(el);
}
const getOffsetSize = getElementAxisSize.bind(null, 'offsetWidth', 'offsetHeight');
const getClientSize = getElementAxisSize.bind(null, 'clientWidth', 'clientHeight');
const invisibleItemQueue = createPriorityQueue((a, b)=>-1 * compareItems(a, b));
const visibleItemQueue = createPriorityQueue(compareItems);
function occupiedSize() {
const totalItemSize = visibleItemQueue.all().map((id)=>overflowItems[id].element).map(getOffsetSize).reduce((prev, current)=>prev + current, 0);
const totalDividerSize = Object.entries(groupManager.groupVisibility()).reduce((acc, [id, state])=>acc + (state !== 'hidden' && overflowDividers[id] ? getOffsetSize(overflowDividers[id].element) : 0), 0);
const overflowMenuSize = (invisibleItemQueue.size() > 0 || options.hasHiddenItems) && overflowMenu ? getOffsetSize(overflowMenu) : 0;
return totalItemSize + totalDividerSize + overflowMenuSize;
}
const showItem = ()=>{
const item = getNextItem(invisibleItemQueue, visibleItemQueue);
options.onUpdateItemVisibility({
item,
visible: true
});
if (item.groupId) {
groupManager.showItem(item.id, item.groupId);
if (groupManager.isSingleItemVisible(item.id, item.groupId)) {
var _overflowDividers_item_groupId;
(_overflowDividers_item_groupId = overflowDividers[item.groupId]) === null || _overflowDividers_item_groupId === void 0 ? void 0 : _overflowDividers_item_groupId.element.removeAttribute(DATA_OVERFLOWING);
}
}
};
const hideItem = ()=>{
const item = getNextItem(visibleItemQueue, invisibleItemQueue);
options.onUpdateItemVisibility({
item,
visible: false
});
if (item.groupId) {
if (groupManager.isSingleItemVisible(item.id, item.groupId)) {
var _overflowDividers_item_groupId;
(_overflowDividers_item_groupId = overflowDividers[item.groupId]) === null || _overflowDividers_item_groupId === void 0 ? void 0 : _overflowDividers_item_groupId.element.setAttribute(DATA_OVERFLOWING, '');
}
groupManager.hideItem(item.id, item.groupId);
}
};
const dispatchOverflowUpdate = ()=>{
const visibleItemIds = visibleItemQueue.all();
const invisibleItemIds = invisibleItemQueue.all();
const visibleItems = visibleItemIds.map((itemId)=>overflowItems[itemId]);
const invisibleItems = invisibleItemIds.map((itemId)=>overflowItems[itemId]);
options.onUpdateOverflow({
visibleItems,
invisibleItems,
groupVisibility: groupManager.groupVisibility()
});
};
const processOverflowItems = ()=>{
if (!container) {
return false;
}
sizeCache.clear();
const availableSize = getClientSize(container) - options.padding;
// Snapshot of the visible/invisible state to compare for updates
const visibleTop = visibleItemQueue.peek();
const invisibleTop = invisibleItemQueue.peek();
while(compareItems(invisibleItemQueue.peek(), visibleItemQueue.peek()) > 0){
hideItem(); // hide elements whose priority become smaller than the highest priority of the hidden one
}
// Run the show/hide step twice - the first step might not be correct if
// it was triggered by a new item being added - new items are always visible by default.
for(let i = 0; i < 2; i++){
// Add items until available width is filled - can result in overflow
while(occupiedSize() < availableSize && invisibleItemQueue.size() > 0 || invisibleItemQueue.size() === 1 // attempt to show the last invisible item hoping it's size does not exceed overflow menu size
){
showItem();
}
// Remove items until there's no more overflow
while(occupiedSize() > availableSize && visibleItemQueue.size() > options.minimumVisible){
var _overflowItems_nextItemId;
const nextItemId = visibleItemQueue.peek();
// Never hide pinned items - they should always remain visible
if (nextItemId && ((_overflowItems_nextItemId = overflowItems[nextItemId]) === null || _overflowItems_nextItemId === void 0 ? void 0 : _overflowItems_nextItemId.pinned)) {
break;
}
hideItem();
}
}
// only update when the state of visible/invisible items has changed
return visibleItemQueue.peek() !== visibleTop || invisibleItemQueue.peek() !== invisibleTop;
};
const forceUpdate = ()=>{
if (processOverflowItems() || forceDispatch) {
forceDispatch = false;
dispatchOverflowUpdate();
}
};
const update = debounce(forceUpdate);
const observe = (observedContainer, userOptions)=>{
Object.assign(options, userOptions);
observing = true;
Object.values(overflowItems).forEach((item)=>visibleItemQueue.enqueue(item.id));
container = observedContainer;
disposeResizeObserver = observeResize(container, (entries)=>{
if (!entries[0] || !container) {
return;
}
update();
});
};
const addItem = (item)=>{
if (overflowItems[item.id]) {
return;
}
overflowItems[item.id] = item;
// some options can affect priority which are only set on `observe`
if (observing) {
// Updates to elements might not change the queue tops
// i.e. new element is enqueued but the top of the queue stays the same
// force a dispatch on the next batched update
forceDispatch = true;
visibleItemQueue.enqueue(item.id);
}
if (item.groupId) {
groupManager.addItem(item.id, item.groupId);
item.element.setAttribute(DATA_OVERFLOW_GROUP, item.groupId);
}
update();
};
const addOverflowMenu = (el)=>{
overflowMenu = el;
};
const addDivider = (divider)=>{
if (!divider.groupId || overflowDividers[divider.groupId]) {
return;
}
divider.element.setAttribute(DATA_OVERFLOW_GROUP, divider.groupId);
overflowDividers[divider.groupId] = divider;
};
const removeOverflowMenu = ()=>{
overflowMenu = undefined;
};
const removeDivider = (groupId)=>{
if (!overflowDividers[groupId]) {
return;
}
const divider = overflowDividers[groupId];
if (divider.groupId) {
delete overflowDividers[groupId];
divider.element.removeAttribute(DATA_OVERFLOW_GROUP);
}
};
const removeItem = (itemId)=>{
if (!overflowItems[itemId]) {
return;
}
if (observing) {
// We might be removing an item in an overflow which would not affect the tops,
// but we need to update anyway to update the overflow menu state
forceDispatch = true;
}
const item = overflowItems[itemId];
visibleItemQueue.remove(itemId);
invisibleItemQueue.remove(itemId);
if (item.groupId) {
groupManager.removeItem(item.id, item.groupId);
item.element.removeAttribute(DATA_OVERFLOW_GROUP);
}
sizeCache.delete(item.element);
delete overflowItems[itemId];
update();
};
const disconnect = ()=>{
disposeResizeObserver();
// reset flags
container = undefined;
observing = false;
forceDispatch = true;
// clear all entries
Object.keys(overflowItems).forEach((itemId)=>removeItem(itemId));
Object.keys(overflowDividers).forEach((dividerId)=>removeDivider(dividerId));
removeOverflowMenu();
sizeCache.clear();
};
return {
addItem,
disconnect,
forceUpdate,
observe,
removeItem,
update,
addOverflowMenu,
removeOverflowMenu,
addDivider,
removeDivider
};
}
const createGroupManager = ()=>{
const groupVisibility = {};
const groups = {};
function updateGroupVisibility(groupId) {
const group = groups[groupId];
if (group.invisibleItemIds.size && group.visibleItemIds.size) {
groupVisibility[groupId] = 'overflow';
} else if (group.visibleItemIds.size === 0) {
groupVisibility[groupId] = 'hidden';
} else {
groupVisibility[groupId] = 'visible';
}
}
function isGroupVisible(groupId) {
return groupVisibility[groupId] === 'visible' || groupVisibility[groupId] === 'overflow';
}
return {
groupVisibility: ()=>groupVisibility,
isSingleItemVisible (itemId, groupId) {
return isGroupVisible(groupId) && groups[groupId].visibleItemIds.has(itemId) && groups[groupId].visibleItemIds.size === 1;
},
addItem (itemId, groupId) {
var _groups, _groupId;
var _;
(_ = (_groups = groups)[_groupId = groupId]) !== null && _ !== void 0 ? _ : _groups[_groupId] = {
visibleItemIds: new Set(),
invisibleItemIds: new Set()
};
groups[groupId].visibleItemIds.add(itemId);
updateGroupVisibility(groupId);
},
removeItem (itemId, groupId) {
groups[groupId].invisibleItemIds.delete(itemId);
groups[groupId].visibleItemIds.delete(itemId);
updateGroupVisibility(groupId);
},
showItem (itemId, groupId) {
groups[groupId].invisibleItemIds.delete(itemId);
groups[groupId].visibleItemIds.add(itemId);
updateGroupVisibility(groupId);
},
hideItem (itemId, groupId) {
groups[groupId].invisibleItemIds.add(itemId);
groups[groupId].visibleItemIds.delete(itemId);
updateGroupVisibility(groupId);
}
};
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,89 @@
/**
* @param compare - comparison function for items
* @returns Priority queue implemented with a min heap
*/ export function createPriorityQueue(compare) {
const arr = [];
let size = 0;
const left = (i)=>{
return 2 * i + 1;
};
const right = (i)=>{
return 2 * i + 2;
};
const parent = (i)=>{
return Math.floor((i - 1) / 2);
};
const swap = (a, b)=>{
const tmp = arr[a];
arr[a] = arr[b];
arr[b] = tmp;
};
const heapify = (i)=>{
let smallest = i;
const l = left(i);
const r = right(i);
if (l < size && compare(arr[l], arr[smallest]) < 0) {
smallest = l;
}
if (r < size && compare(arr[r], arr[smallest]) < 0) {
smallest = r;
}
if (smallest !== i) {
swap(smallest, i);
heapify(smallest);
}
};
const dequeue = ()=>{
if (size === 0) {
throw new Error('Priority queue empty');
}
const res = arr[0];
arr[0] = arr[--size];
heapify(0);
return res;
};
const peek = ()=>{
if (size === 0) {
return null;
}
return arr[0];
};
const enqueue = (item)=>{
arr[size++] = item;
let i = size - 1;
let p = parent(i);
while(i > 0 && compare(arr[p], arr[i]) > 0){
swap(p, i);
i = p;
p = parent(i);
}
};
const contains = (item)=>{
const index = arr.indexOf(item);
return index >= 0 && index < size;
};
const remove = (item)=>{
const i = arr.indexOf(item);
if (i === -1 || i >= size) {
return;
}
arr[i] = arr[--size];
heapify(i);
};
const clear = ()=>{
size = 0;
};
const all = ()=>{
return arr.slice(0, size);
};
return {
all,
clear,
contains,
dequeue,
enqueue,
peek,
remove,
size: ()=>size
};
}

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/priorityQueue.ts"],"sourcesContent":["export type PriorityQueueCompareFn<T> = (a: T, b: T) => number;\n\nexport interface PriorityQueue<T> {\n all: () => T[];\n clear: () => void;\n contains: (item: T) => boolean;\n dequeue: () => T;\n enqueue: (item: T) => void;\n peek: () => T | null;\n remove: (item: T) => void;\n size: () => number;\n}\n\n/**\n * @param compare - comparison function for items\n * @returns Priority queue implemented with a min heap\n */\nexport function createPriorityQueue<T>(compare: PriorityQueueCompareFn<T>): PriorityQueue<T> {\n const arr: T[] = [];\n let size = 0;\n\n const left = (i: number) => {\n return 2 * i + 1;\n };\n\n const right = (i: number) => {\n return 2 * i + 2;\n };\n\n const parent = (i: number) => {\n return Math.floor((i - 1) / 2);\n };\n\n const swap = (a: number, b: number) => {\n const tmp = arr[a];\n arr[a] = arr[b];\n arr[b] = tmp;\n };\n\n const heapify = (i: number) => {\n let smallest = i;\n const l = left(i);\n const r = right(i);\n\n if (l < size && compare(arr[l], arr[smallest]) < 0) {\n smallest = l;\n }\n\n if (r < size && compare(arr[r], arr[smallest]) < 0) {\n smallest = r;\n }\n\n if (smallest !== i) {\n swap(smallest, i);\n heapify(smallest);\n }\n };\n\n const dequeue = () => {\n if (size === 0) {\n throw new Error('Priority queue empty');\n }\n\n const res = arr[0];\n arr[0] = arr[--size];\n heapify(0);\n\n return res;\n };\n\n const peek = () => {\n if (size === 0) {\n return null;\n }\n\n return arr[0];\n };\n\n const enqueue = (item: T) => {\n arr[size++] = item;\n let i = size - 1;\n let p = parent(i);\n while (i > 0 && compare(arr[p], arr[i]) > 0) {\n swap(p, i);\n i = p;\n p = parent(i);\n }\n };\n\n const contains = (item: T) => {\n const index = arr.indexOf(item);\n return index >= 0 && index < size;\n };\n\n const remove = (item: T) => {\n const i = arr.indexOf(item);\n\n if (i === -1 || i >= size) {\n return;\n }\n\n arr[i] = arr[--size];\n heapify(i);\n };\n\n const clear = () => {\n size = 0;\n };\n\n const all = () => {\n return arr.slice(0, size);\n };\n\n return {\n all,\n clear,\n contains,\n dequeue,\n enqueue,\n peek,\n remove,\n size: () => size,\n };\n}\n"],"names":["createPriorityQueue","compare","arr","size","left","i","right","parent","Math","floor","swap","a","b","tmp","heapify","smallest","l","r","dequeue","Error","res","peek","enqueue","item","p","contains","index","indexOf","remove","clear","all","slice"],"mappings":"AAaA;;;CAGC,GACD,OAAO,SAASA,oBAAuBC,OAAkC;IACvE,MAAMC,MAAW,EAAE;IACnB,IAAIC,OAAO;IAEX,MAAMC,OAAO,CAACC;QACZ,OAAO,IAAIA,IAAI;IACjB;IAEA,MAAMC,QAAQ,CAACD;QACb,OAAO,IAAIA,IAAI;IACjB;IAEA,MAAME,SAAS,CAACF;QACd,OAAOG,KAAKC,KAAK,CAAC,AAACJ,CAAAA,IAAI,CAAA,IAAK;IAC9B;IAEA,MAAMK,OAAO,CAACC,GAAWC;QACvB,MAAMC,MAAMX,GAAG,CAACS,EAAE;QAClBT,GAAG,CAACS,EAAE,GAAGT,GAAG,CAACU,EAAE;QACfV,GAAG,CAACU,EAAE,GAAGC;IACX;IAEA,MAAMC,UAAU,CAACT;QACf,IAAIU,WAAWV;QACf,MAAMW,IAAIZ,KAAKC;QACf,MAAMY,IAAIX,MAAMD;QAEhB,IAAIW,IAAIb,QAAQF,QAAQC,GAAG,CAACc,EAAE,EAAEd,GAAG,CAACa,SAAS,IAAI,GAAG;YAClDA,WAAWC;QACb;QAEA,IAAIC,IAAId,QAAQF,QAAQC,GAAG,CAACe,EAAE,EAAEf,GAAG,CAACa,SAAS,IAAI,GAAG;YAClDA,WAAWE;QACb;QAEA,IAAIF,aAAaV,GAAG;YAClBK,KAAKK,UAAUV;YACfS,QAAQC;QACV;IACF;IAEA,MAAMG,UAAU;QACd,IAAIf,SAAS,GAAG;YACd,MAAM,IAAIgB,MAAM;QAClB;QAEA,MAAMC,MAAMlB,GAAG,CAAC,EAAE;QAClBA,GAAG,CAAC,EAAE,GAAGA,GAAG,CAAC,EAAEC,KAAK;QACpBW,QAAQ;QAER,OAAOM;IACT;IAEA,MAAMC,OAAO;QACX,IAAIlB,SAAS,GAAG;YACd,OAAO;QACT;QAEA,OAAOD,GAAG,CAAC,EAAE;IACf;IAEA,MAAMoB,UAAU,CAACC;QACfrB,GAAG,CAACC,OAAO,GAAGoB;QACd,IAAIlB,IAAIF,OAAO;QACf,IAAIqB,IAAIjB,OAAOF;QACf,MAAOA,IAAI,KAAKJ,QAAQC,GAAG,CAACsB,EAAE,EAAEtB,GAAG,CAACG,EAAE,IAAI,EAAG;YAC3CK,KAAKc,GAAGnB;YACRA,IAAImB;YACJA,IAAIjB,OAAOF;QACb;IACF;IAEA,MAAMoB,WAAW,CAACF;QAChB,MAAMG,QAAQxB,IAAIyB,OAAO,CAACJ;QAC1B,OAAOG,SAAS,KAAKA,QAAQvB;IAC/B;IAEA,MAAMyB,SAAS,CAACL;QACd,MAAMlB,IAAIH,IAAIyB,OAAO,CAACJ;QAEtB,IAAIlB,MAAM,CAAC,KAAKA,KAAKF,MAAM;YACzB;QACF;QAEAD,GAAG,CAACG,EAAE,GAAGH,GAAG,CAAC,EAAEC,KAAK;QACpBW,QAAQT;IACV;IAEA,MAAMwB,QAAQ;QACZ1B,OAAO;IACT;IAEA,MAAM2B,MAAM;QACV,OAAO5B,IAAI6B,KAAK,CAAC,GAAG5B;IACtB;IAEA,OAAO;QACL2B;QACAD;QACAJ;QACAP;QACAI;QACAD;QACAO;QACAzB,MAAM,IAAMA;IACd;AACF"}

View File

@@ -0,0 +1,3 @@
/**
* @internal
*/ export { };

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type OverflowDirection = 'start' | 'end';\nexport type OverflowAxis = 'horizontal' | 'vertical';\nexport type OverflowGroupState = 'visible' | 'hidden' | 'overflow';\nexport interface OverflowItemEntry {\n /**\n * HTML element that will be disappear when overflowed\n */\n element: HTMLElement;\n /**\n * Lower priority items are invisible first when the container is overflowed\n * @default 0\n */\n priority: number;\n /**\n * Specific id, used to track visibility and provide updates to consumers\n */\n id: string;\n\n groupId?: string;\n\n /**\n * If true, the item will never overflow and will always be visible.\n * Pinned items are excluded from the overflow count.\n * @default false\n */\n pinned?: boolean;\n}\n\nexport interface OverflowDividerEntry {\n /**\n * HTML element that will disappear when overflowed\n */\n element: HTMLElement;\n\n groupId: string;\n}\n\n/**\n * signature similar to standard event listeners, but typed to handle the custom event\n */\nexport type OnUpdateOverflow = (data: OverflowEventPayload) => void;\n\nexport type OnUpdateItemVisibility = (data: OnUpdateItemVisibilityPayload) => void;\n\n/**\n * Payload of the custom DOM event for overflow updates\n */\nexport interface OverflowEventPayload {\n visibleItems: OverflowItemEntry[];\n invisibleItems: OverflowItemEntry[];\n groupVisibility: Record<string, OverflowGroupState>;\n}\n\nexport interface OnUpdateItemVisibilityPayload {\n item: OverflowItemEntry;\n visible: boolean;\n}\n\nexport interface ObserveOptions {\n /**\n * Padding (in px) at the end of the container before overflow occurs\n * Useful to account for extra elements (i.e. dropdown menu)\n * or to account for any kinds of margins between items which are hard to measure with JS\n * @default 10\n */\n padding?: number;\n /**\n * Direction where items are removed when overflow occurs\n * @default end\n */\n overflowDirection?: OverflowDirection;\n\n /**\n * Horizontal or vertical overflow\n * @default horizontal\n */\n overflowAxis?: OverflowAxis;\n\n /**\n * The minimum number of visible items\n */\n minimumVisible?: number;\n\n /**\n * Callback when item visibility is updated\n */\n onUpdateItemVisibility: OnUpdateItemVisibility;\n\n /**\n * Callback when item visibility is updated\n */\n onUpdateOverflow: OnUpdateOverflow;\n\n /**\n * When true, the overflow menu has default hidden items\n * @default false\n */\n hasHiddenItems?: boolean;\n}\n\n/**\n * @internal\n */\nexport interface OverflowManager {\n /**\n * Starts observing the container and managing the overflow state\n */\n observe: (container: HTMLElement, options: ObserveOptions) => void;\n /**\n * Stops observing the container\n */\n disconnect: () => void;\n /**\n * Add overflow items\n */\n addItem: (items: OverflowItemEntry) => void;\n /**\n * Remove overflow item\n */\n removeItem: (itemId: string) => void;\n /**\n * Manually update the overflow, updates are batched and async\n */\n update: () => void;\n /**\n * Manually update the overflow sync\n */\n forceUpdate: () => void;\n\n /**\n * Adds an element that opens an overflow menu. This is used to calculate\n * available space and check if additional items need to overflow\n */\n addOverflowMenu: (element: HTMLElement) => void;\n\n /**\n * Add overflow divider\n */\n addDivider: (divider: OverflowDividerEntry) => void;\n\n /**\n * Remove overflow divider\n */\n removeDivider: (groupId: string) => void;\n\n /**\n * Unsets the overflow menu element\n */\n removeOverflowMenu: () => void;\n}\n"],"names":[],"mappings":"AAoGA;;CAEC,GACD,WA8CC"}