@wener/console
Version:
Base console UI toolkit
90 lines (89 loc) • 3.26 kB
JavaScript
import React, { memo, useCallback, useDebugValue, useEffect, useId } from "react";
import { useCompareEffect } from "@wener/reaction";
import { createStore } from "zustand";
import { immer } from "zustand/middleware/immer";
import { shallow } from "zustand/shallow";
import { createStoreContext } from "../../zustand/index.js";
const createSlotStore = () => createStore()(immer(() => ({
slots: {}
})));
export function createSlotContext() {
const { Provider, useStore, useStoreApi } = createStoreContext();
const SlotProvider = ({ children }) => {
return /*#__PURE__*/ React.createElement(Provider, {
createStore: createSlotStore
}, children);
};
const Slot = /*#__PURE__*/ memo(({ name, placement = "default", order = 0, children }) => {
const api = useStoreApi();
const slotId = useId();
placement ||= "default";
order ||= 0;
const slotPlace = `${name}/${placement}`;
useCompareEffect(() => {
// wrap children with key
api.setState((s) => {
const slots = s.slots[slotPlace] ||= [];
const slot = slots.find((v) => v.id === slotId);
if (slot) {
Object.assign(slot, {
name,
placement,
order,
children
});
}
else {
slots.push({
id: slotId,
name,
placement,
order,
children
});
}
slots.sort((a, b) => b.order - a.order);
});
}, [
slotPlace,
order,
children
]);
useEffect(() => {
return () => {
api.setState((s) => {
s.slots[slotPlace] = s.slots[slotPlace]?.filter((v) => v.id !== slotId);
});
};
}, []);
useDebugValue(`Slot ${slotPlace}@{${slotId}`);
return null;
});
Slot.displayName = "Slot";
function useSlot({ name, placement }) {
const slotPlace = `${name}/${placement || "default"}`;
return useStore(useCallback((s) => s.slots[slotPlace] || [], [
slotPlace
]), shallow);
}
const SlotPlaceholder = /*#__PURE__*/ memo(({ name, placement, placeholder }) => {
const slotPlace = `${name}/${placement || "default"}`;
const slot = useStore(useCallback((s) => s.slots[slotPlace] || [], [
slotPlace
]), shallow);
useDebugValue(`SlotPlaceholder ${name}${placement ? `@${placement}` : ""}`);
const children = slot.length ? slot.map((v) => {
return v.children;
}) : placeholder;
return /*#__PURE__*/ React.createElement(React.Fragment, null, children);
});
SlotPlaceholder.displayName = "SlotPlaceholder";
return {
Slot,
useSlot,
SlotPlaceholder,
SlotProvider
};
}
export const { Slot, SlotPlaceholder, SlotProvider, useSlot } = createSlotContext();
//# sourceMappingURL=Slot.js.map