UNPKG

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
"use strict"; 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); } }