npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@gsandf/ui

v0.4.0-beta.1

Published

⚡ A simple set of UI development helpers for React projects

Downloads

15

Readme

@gsandf/ui

⚡ A simple set of UI development helpers for React projects

Install

Using Yarn:

$ yarn add @gsandf/ui react react-dom styled-components@^5.3.0

…or using [npm]:

$ npm i --save @gsandf/ui react react-dom styled-components@^5.3.0

Setup Theme

If you plan to use the components, most require a ThemeProvider be set up.

You can do this easily using the default theme. For example:

import { createTheme, defaultTheme } from '@gsandf/ui';
import { ThemeProvider } from 'styled-components';

const theme = createTheme({ ...defaultTheme });
const GlobalStyles = theme.styles;

export default function App({ children }) {
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyles />

      {children}
    </ThemeProvider>
  );
}

To see how to customize the theme, check out the Theme section.

Components

Controls

  • <Button /> - A simple button component with basic default styles

Layout

  • <AspectRatio /> - A <Box /> with a fixed width/height ratio
  • <BasicGrid /> - A basic grid component that distributes its children evenly
  • <Box /> - A simple box. By default, it renders a <div />.
  • <Center /> - A <Flex /> with flex properties set to center content.
  • <Container /> - Constrains content width with a default max size
  • <Flex /> - A box with display: flex
  • <Hide /> - Helper to set display: none based on a media query
  • <NoServerRender /> - Renders its children only on the client after hydration.
  • <ScreenReaderContent /> - Hides content visually but remains accessible to screen readers.
  • <Stack /> - Stack is a Flex with helpers to add spacing between elements. The default direction is a column.
  • <HStack /> - HStack is a Flex with helpers to add spacing between elements. It lays out its children horizontally and centers them vertically.
  • <VStack /> - VStack is a Flex with helpers to add spacing between elements. It lays out its children vertically and centers them horizontally.

Typography

  • <Text /> - Render text. It accepts all theme mixins as props, has helpers for truncating text, and by default retains newlines (for rendering text from an API response).

Hooks

useBreakpoint()

Returns the name of the current breakpoint. If breakpointFilter is given, returns the name of the largest breakpoint that matches the current window.

function BasicUsage() {
  const breakpoint = useBreakpoint();

  return <div>The current breakpoint is {breakpoint}</div>;
}
function WithFilteredBreakpoints() {
  const breakpoint = useBreakpoint(['md', 'xxl']);

  return (
    <div>
      Of `base`, `md`, and `xxl`, the current breakpoint is {breakpoint}
    </div>
  );
}

useBreakpointValue()

Returns a value based on the current window size.

function BasicUsage() {
  const bgColor = useBreakpointValue({
    base: 'gray900',
    sm: 'gray700',
    md: 'gray600',
    lg: 'gray400',
    xl: 'gray200',
    xxl: 'gray100'
  });

  const fgColor = useBreakpointValue({
    base: 'black',
    lg: 'white'
  });

  return (
    <Center $bgColor={bgColor} $color={fgColor}>
      Adjust the screen size!
    </Center>
  );
}

useClickedOutside()

Handles click events outside a DOM element, like a div. A handler function is invoked when a click or touch event happens outside the referenced element.

function Example() {
  const containerRef = useRef(null);
  useClickedOutside(containerRef, () => alert('clicked outside'));

  return (
    <Center>
      <VStack>
        <Box ref={containerRef}>
          Click outside this box to trigger an alert!
        </Box>
      </VStack>
    </Center>
  );
}

useDebouncedState()

Saves a value like useState, but delays setting the value until delay milliseconds has passed.

function Example() {
  const [triggerCount, setTriggerCount] = useDebouncedState(0);

  const incrementTriggerCount = () => {
    setTriggerCount(n => n + 1);
  };

  useEffect(() => {
    document.addEventListener('mousemove', incrementTriggerCount);

    return () => {
      document.removeEventListener('mousemove', incrementTriggerCount);
    };
  });

  return <div>Times triggered: {triggerCount}</div>;
}

useLocalStorage()

Saves a value in localStorage so it can be persisted between page refresh. This hook is used similar to useState, but the first argument is the key used to save/lookup the value in localStorage.

If localStorage isn't available - such as during a server render - the initial value will be returned.

function Example() {
  const [value, setValue] = useLocalStorage('exampleKey', 0);

  return (
    <div>
      <Box>Value stored in localStorage: {value}</Box>

      <HStack>
        <Button onClick={() => setValue(value => value - 1)}>-</Button>
        <Button onClick={() => setValue(0)}>Reset</Button>
        <Button onClick={() => setValue(value => value + 1)}>+</Button>
      </HStack>
    </div>
  );
}

useMediaQuery()

Detects when a media query matches the current window.

function Example() {
  const isLargerThan1000 = useMediaQuery('(min-width: 1000px)');

  return (
    <Box>
      Is the screen at least 1000px wide? {isLargerThan1000 ? 'yes' : 'no'}
    </Box>
  );
}

useModalCloseEvent()

Calls the given onClose function when a common event outside a modal should trigger a close. For example, this can handle when the Escape key is pressed and when the modal is clicked outside.

function ExampleModal({ onClose }) {
  const containerRef = useRef(null);

  useModalCloseEvent(onClose, containerRef);

  return (
    <VStack ref={containerRef}>
      <Box>
        This modal will close if the escape key is pressed or if clicked outside
        of.
      </Box>
    </VStack>
  );
}

Theme

A theme is an object that follows a certain shape. The idea for the shape was originally taken from the System UI theme specification. Most of the theme shouldn't rely on a certain build system, framework, etc.

For the most part, we've kept the same ideas, but we allow relying on certain styling ideas (e.g. media queries, global styles, component styles) that may rely on certain tools being available.

Here's the interface for a theme:

interface CustomTheme {
  borders?: Record<string, CSSProperties['border']>;
  breakpoints?: Record<string, number>;
  colors?: Record<string, CSSProperties['backgroundColor']>;
  components?: ComponentStyles;
  fonts?: Record<string, CSSProperties['fontFamily']>;
  fontSizes?: CSSProperties['fontSize'][];
  fontWeights?: Record<string, CSSProperties['fontWeight']>;
  lineHeights?: Record<string, CSSProperties['lineHeight']>;
  radii?: Record<string, CSSProperties['borderRadius']>;
  shadows?: Record<string, CSSProperties['boxShadow']>;
  sizes?: Record<string | number, string>;
  space?: (string | number)[] | Record<string | number, string>;
  styles?: GlobalStyleComponent<unknown, unknown> | (() => ReactElement);
  transitions?: GlobalStyleComponent<unknown, CSSProperties['transition']>;
  zIndices?: Record<string, CSSProperties['zIndex']>;
}

export type ComponentStyles = Record<
  string,
  {
    baseStyle?: CSSProp<unknown>;
    variants?: Record<string, CSSProp<unknown>>;
  }
>;

defaultTheme

A base reference theme that can be expanded easily.

import { defaultTheme } from '@gsandf/ui';

createTheme(themeObject)

Takes a theme object and extends it with media and mixins to it. media is a set of CSS breakpoint helpers. mixins are a set of utilities for making flexible styled components.

import { defaultTheme } from '@gsandf/ui';

const coolWebsiteTheme = {
  ...defaultTheme,
  colors: {
    primary: '#f00',
    onPrimary: '#fff',
    secondary: '#ff0',
    onSecondary: '#000',
    transparent: 'transparent',
    white: '#ffffff'
  },
  fonts: {
    body: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',
    heading:
      'Roboto Condensed, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',
    monospace: 'IBM Plex Mono, Menlo, monospace'
  },
  lineHeights: {
    body: 1.7,
    control: 1.2,
    heading: 1.2
  },
  shadows: {
    default: `0 0 2px 0 #00000004`
  }
};

const theme = createTheme(coolWebsiteTheme);

Utilities

  • isServer / isBrowser - booleans for checking if the current rendering environment is on the server or in a browser.
  • ensureUnit(value, unit) - Makes sure a given value has a unit at the end. The default unit is px. Also accepts an array of values.
  • noop() - Empty function
  • omit(object, key) - Shallow omit a property from an object
  • type StyledComponentProps<T> - Helper to extract type of props from a Styled Component.

Contributing

Node.js and Yarn are required to work with this project.

To install all dependencies, run:

yarn

Then, you can start Storybook to test changes:

yarn dev

See below for other scripts.

Useful Commands

| | | | ------------------- | --------------------------------------------------------------------------- | | yarn build | Builds the project to ./dist | | yarn dev | Starts the Storybook server | | yarn test | Run project tests | | yarn test --watch | Run project tests, watching for file changes | | yarn type-check | Check the project for TypeScript errors | | yarn validate | Runs tests, checks formatting, lints code, and checks for TypeScript errors |

License

UNLICENSED