nano-slots
Version:
A super lightweight modern alternative to [`react-slot-fill`](https://github.com/camwest/react-slot-fill) with familiar API.
80 lines (79 loc) • 2.83 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createEmitter = exports.Fill = exports.Slot = exports.SlotsProvider = void 0;
var react_1 = require("react");
var is_server_1 = __importDefault(require("./is-server"));
exports.SlotsProvider = (_a = createSlots(), _a.Provider), exports.Slot = _a.Slot, exports.Fill = _a.Fill;
function createSlots() {
var SlotsContext = (0, react_1.createContext)(createEmitter());
function Provider(props) {
var emitter = (0, react_1.useState)(createEmitter)[0];
return ((0, react_1.createElement)(SlotsContext.Provider, { value: emitter }, props.children));
}
function Slot(props) {
var emitter = (0, react_1.useContext)(SlotsContext);
var _a = (0, react_1.useState)(), node = _a[0], setNode = _a[1];
useUniversalEffect(function () {
setNode(emitter.get(props.name));
return emitter.on(props.name, setNode);
}, [emitter, props.name]);
var has = node !== undefined;
useUniversalEffect(function () {
if (props.onChange)
props.onChange(has);
}, [has, props.onChange]);
return (0, react_1.createElement)(react_1.Fragment, null, has ? node : props.children);
}
function Fill(props) {
var emitter = (0, react_1.useContext)(SlotsContext);
useUniversalEffect(function () {
return emitter.emit(props.name, props.children);
}, [emitter, props.name, props.children]);
return null;
}
return {
Provider: Provider,
Slot: Slot,
Fill: Fill,
};
}
exports.default = createSlots;
/** @private Don't use! */
function createEmitter() {
var cache = {};
var events = {};
function update(event, node) {
var source = events[event];
if (source)
source.forEach(function (cb) { return cb(node); });
cache[event] = node;
}
return {
emit: function (event, node) {
update(event, node);
return function () { return update(event); };
},
get: function (event) {
return cache[event];
},
on: function (event, cb) {
var source = (events[event] = events[event] || []);
source.push(cb);
return function () {
var index = source.indexOf(cb);
if (index > -1)
source.splice(index, 1);
};
},
};
}
exports.createEmitter = createEmitter;
function useUniversalEffect(effect, deps) {
if (!(0, is_server_1.default)()) {
(0, react_1.useLayoutEffect)(effect, deps);
}
}