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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ws-serenity/react-attachments

v1.2.1

Published

React component for attachments

Readme

@ws-serenity/react-attachments

Repository

TODO

В общем. Поместить запросы в либу. И сделать сетап для них подобный тому, как работают api-requests. Его один раз делаешь и все. Нужно будет передать просто api туда, а возвращаем мы уже AttachmentApi с getAll(ids).

А в компоненте мы все же не будем по умолчанию использовать их. Пусть пропсом передается initial с промисом:

<AttachmentContainer
    customDragComponent={<CustomActiveDrag />}
    className={'sample-attachment-container'}
    showAttachedFiles={true}
    uploadComponent={CustomUploadComponent}
    handleSubmit={filesRef}
    initialAttachments={attachmentApi.getAll(ids)}
    // интерфейсом мы ограничим наличие "getAll", здесь он нам больше не нужен будет
    attachmentApi={attachmentsApi}
    downloadComponent={DownloadButton}
    deleteComponent={DeleteButton}
/>;
// inside useAttachmentDataHandler
useEffect(()=>{
    initialAttachments.then(resp=>setApiAttachments(resp.items))
},[])

About

Концепция - максимально настраиваемый без лишних стилей. Не подходит по дизайну? Используй вспомогательные хуки и настрой самостоятельно!

Компонент не создает самостоятельно аттачменты. Но удаляет существующие (над этим стоит еще подумать). Поэтому можно сказать, что им полностью управляет внешняя форма.

Иными словами, всегда хранится два состояния:

  1. Что пришло с API
  2. Что добавил пользователь, но еще не отправил

Если это необходимо, можно будет создать настройку этого поведения.

Отправка формы аттачментов

Необходимо выполнять "вручную". Это сделано, чтобы лишний раз не нагружать сеть при удалении/добавлении элементов. Запросы отправляются параллельно.

Пример:

export function SomeFormWithAttachments(){
    const filesRef = useExtractApiData();

    async function handleSubmit(e: any) {
        e.preventDefault();
        if (!filesRef.current) return;
        
        // make component send create requests
        const files = await filesRef.current.extract();
        // now u can submit form with attachmentIds
    }

    return (
        <form
            action={'#'}
            className={'test-container'}
            onSubmit={handleSubmit}
        >
            <AttachmentContainer
                customDragComponent={<CustomActiveDrag/>}
                className={'sample-attachment-container'}
                showAttachedFiles={true}
                handleSubmit={filesRef}
                uploadComponent={CustomUploadComponent}
                attachmentApi={attachmentsApi}
                downloadComponent={DownloadButton}
                deleteComponent={DeleteButton}
            />
            <button className={'test-container__submit'}>
                Submit
            </button>
        </form>
    );
}

// You can override default Component on active drag (if it's enabled)
const CustomActiveDrag = () => (
    <div className={'custom-active-drop'}>
        <p>Drop your files here</p>
        <UploadIcon/>
    </div>
);

// You must define buttons to delete and remove attachment if u want to use built-in AttachmentItem-component
// You can define your own behaviour using "AttachmentCustomItem" type
const DownloadButton = (props: ActionProps) => (
    <button
        type={'button'}
        onClick={props.onClick}
        className={clsx(props.className, 'sample-attachment-container__attachment-button')}
    >
        <DownloadIcon/>
    </button>
);

const DeleteButton = (props: ActionProps) => (
    <button
        type={'button'}
        onClick={props.onClick}
        className={clsx(props.className, 'sample-attachment-container__attachment-button')}
    >
        <DeleteIcon/>
    </button>
);

// U can also define custom component to upload files. 
// It's displayed when component is empty or user can upload more files
// You can manage It's behaviour using css-styling. Component has to state-classes (read further)
const CustomUploadComponent = (props:UploadComponentProps) => (
    <div onClick={props.handleUploadClick} className={props.className}>
        <p>Drop your files here</p>
    </div>
)

State-styles

  1. Когда компонент не содержит вложений, он имеет стиль: ws-attachment-container--empty
  2. При активном drag-and-drop добавляется ws-attachments-container--drag-active

В большинстве случаев, следует добавлять классы, передаваемые в пропсы к кастомным компонентам. Они могут содержать важные стили для состояния.

Limitations

Пока что все кастомные JSX-элементы (JSXElementConstructor<Props>) не могут иметь каких-либо дополнительных пропсов, что сильно ограничивает их функционал. Вскоре планируется добавить