Code Monkey home page Code Monkey logo

nano-slots's Introduction

nano-slots

A super lightweight modern alternative to react-slot-fill with familiar API.

  • Control sub-components rendering with Slot and Fill
  • Render content of sub-component in multiple places
  • Speedy - Fill and Slot communicate directly with each other
  • Tested with testing-library
  • Written in TypeScript
  • Zero dependencies
  • Only ~431 B

๐Ÿ“ฆ Install

npm i -S nano-slots
yarn add nano-slots

๐Ÿ’ป Usage

Create a component and define slots

import { Box, Flex } from 'theme-ui'
import { SlotsProvider, Slot } from 'nano-slots'

export const MediaObject = ({ children }) => (
  <SlotsProvider>
    <Flex>
      <Box mr={3}>
        <Slot name="media-side" />
      </Box>
      <Box>
        <Box mb={2}>
          <Slot name="media-title" />
        </Box>
        <Box>
          <Slot name="media-description" />
        </Box>
        {children}
      </Box>
    </Flex>
  </SlotsProvider>
)

Render elements directly inside each slot

import { Fill } from 'nano-slots'
import { MediaObject } from './media-object'

const MyApp = () => (
  <MediaObject>
    <Fill name="media-side">
      <img src='https://placekitten.com/200' alt="Kitten" />
    </Fill>
    <Fill name="media-title">
      <h3>Mew</h3>
    </Fill>
    <Fill name="media-description">
      <p>Purr purr purr</p>
    </Fill>
  </MediaObject>
)

Edit nano-slots

๐Ÿ“– API

SlotsProvider

import { SlotsProvider } from 'nano-slots'

Props

  • children: ReactNode โ€” any valid react children element

Description

Creates a context for Slot / Fill components.

Slot

import { Slot } from 'nano-slots'

Props

  • name: string โ€” unique slot name for current SlotsProvider
  • children?: ReactNode โ€” fallback in case Fill with matching name not provided, optional
  • onChange?(hasFilled: boolean): void โ€” callback for detecting state changes, on true children of matching Fill is rendered and fallback is hidden

Description

Define the target slot for Fill component. Can be used multiple times with the same name inside each SlotsProvider.

Fill

import { Fill } from 'nano-slots'

Props

  • name: string โ€” unique slot name for current SlotsProvider
  • children: ReactNode โ€” will be rendered inside matching Slot

Description

Render children into matching Slot of current SlotsProvider.

createSlots

import createSlots from 'nano-slots'

Description

Designed for more advanced usages and stronger types. Returns an object containing:

  • .Provider โ€” same as SlotsProvider, but with different context
  • .Slot โ€” same as Slot, but with own context
  • .Fill โ€” same as Fill, but with own context

Returned Slot and Fill can be used without a Provider.

Types

export interface ProviderProps {
  children: React.ReactNode;
}

export function SlotsProvider(props: ProviderProps): JSX.Element;

export interface SlotProps<Names extends PropertyKey> {
  name: Names;
  children?: React.ReactNode;
}

export function Slot(props: SlotProps): JSX.Element;

export interface FillProps<Names extends PropertyKey> {
  name: Names;
  children?: React.ReactNode;
}

export function Fill(props: FillProps): null;

export default function createSlots<Names extends PropertyKey>(): {
  Provider: (props: SlotsProviderProps): JSX.Element;
  Slot: (props: SlotProps<Names>): JSX.Element;
  Fill: (props: FillProps<Names>): null;
}

Alternatives


MIT ยฉ John Grishin

nano-slots's People

Contributors

exah avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

nano-slots's Issues

Rendering more than one.

Hello, thank you for this library. I am switching from react-fill-slots library to yours, because of keeps updating with the new ReactJs version. I am trying to solve one problem. Let me give you an example.

This is my component where I am using Fill with name Sidebar.Content

`export default function Sidebar({ label, order, children, renderDontFill = false }) {
  const content = (
    <Section order={order}>
      <Header>{label}</Header>
      {children}
    </Section>
  );
  return renderDontFill ? content : <Fill name="Sidebar.Content">{content}</Fill>;
}`

This is my component where I am using <Slot name="Sidebar.Content>


function Sidebar() {
          <SlotsProvider>
              <Slot name="Sidebar.Content">
                {(elements) => (
                  <div>
                    {elements.sort((l, r) => (l.props.order || 1000) - (r.props.order || 1000))}
                  </div>
                )}
          </SlotsProvider>    
  );
}

if content In Sidebar is more than one it always displays the last one. In previous library react-slot-fill there is functionality of getting byName which returns Fill[] . Is there a way to solve this with your library ?

Some method for communicating between the slot and the fill

The Fill frequently needs to access data from the Slot to render correctly, so not having some means of doing that(similar to params in react-view-slot) is problematic for our use case.

Is there some way to achieve this that I'm missing?

Support for react 18.2

The package peerDeps specify react 16/17 only.
This fails on recent npm unless --legacy-peer-deps is used.

Context behaviour like Portals

Hello,

We use react-router v6 which supports relative links. In order to make it works properly the components need to behave like they do when rendered as a Portal. So no matter where they are physically rendered in the DOM they still follow the virtual tree structure and have access to any context wrapping them.

I noticed that this library is breaking this behaviour, so we can't use relative links in components "sent" in our Layout.

Do you think there could be a way to match Portals in term of Context consumption?

Slots hold on to their fill state after nothing is rendering into them.

I'm pretty sure there are issues with the way that null state is tracked for Slots.

This issue came up in two specific situations.

  1. Let's say we have SlotA and SlotB and then a single Fill. If the fill is rendering into SlotA and then I change its name so that it renders into SlotB, Both SlotA and SlotB have the fill content rendered into them.
  2. If have a component that renders a Fill, and then just returns null(where it's no longer rendering the fill at all) the Slot holds on to the fill content.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.