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

@kaiju.ui2/components

v0.0.4

Published

This README would normally document whatever steps are necessary to get your application up and running.

Downloads

4

Readme

README

Core package of kaiju.components;

Components list (docs checklist)

  • Table (DONE)
  • Header (DONE)
  • Buttons (DONE)
  • Notifications (DONE)
  • SearchComponent and SearchBox (DONE)
  • Select\MultiSelect Component
  • Tabs (DONE)
  • WindowActionComponent
  • Checkbox and Radio
  • Modals
  • BaseStorage (DONE)

Table

Options

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |request | json | method и params grid-метода | - | yes | |rowCallback | function | функция возвращающая id строчки на click | false | No | |autoRefresh | integer | включает обновление данных каждые n секунд | "Количество" | No | |ActionsComponent | component | компонент правой ячейки записи: удаление, редактирование и тд | "Количество" | No | |labelCount | string | лейбл счетчика около пагинации | "Количество" | No | |disableCount | bool | убрать счетчик около пагинации | false | No | |disablePagination | bool | убрать пагинацию | false | No | |checkable | bool | включает режим чекбоксов | false | No | |checkCallback | bool | колбек на | false | No | |accordion | bool | разделение таблицы на группы | false | No | |cellConstructors | json | # TODO: | false | No | |fieldConstructors | json | # TODO: | false | No |

Methods and stores

TODO: count, checkedIds, rowStore, all actions

tableStore.actions.isFetching - идёт ли запрос на бек в текущий момент времени this.props.tableStore.actions.fetchByPage() - получить страницу. Можно передать номер страницы, по-умолчанию получает первую.

Usage

import React from "react";
import TableComponent from "@kaiju.ui/components/src/Tables/TableComponent";
import {Provider} from "mobx-react";
import {TableStore} from "@kaiju.ui/components/src/Tables/stores";


class SomeComp extends React.Component {
    constructor(props) {
        super(props)

        this.tableStore = new TableStore({
            request: {
                method: "Product.grid", // метод отвечающий за построение таблицы
                params: { // параметры
                    engine: this.engineId,
                }
            },
            rowCallback: (rowStore) => {
                this.props.routerStore.router.navigate(ROUTES.invoiceEdit, {id: rowStore.id})
            }
        });
    }

    render() {
        return (
            <Provider tableStore={this.tableStore}>
                <TableComponent/>
            </Provider>
        )
    }
}

Пример с table actions component:

import {TableStore} from "@kaiju.ui/components/src/Tables/stores";
import TableComponent from "Tables/TableComponent";
import React from "react";
import {Provider} from "mobx-react";
import ROUTES from "smtg"
import ActionsComponent, {DeleteAction} from "@kaiju.ui/components/src/Tables/actions";


@inject("routerStore")
@inject("userStore")
class TableActionsComponent extends React.Component {

    delete() {
        Axios.post(ROUTES.rpc,
            {
                "method": `${this.props.serviceName}.delete`,
                "params": {
                    engine: this.props.routerStore.route.params["engineId"],
                    key: this.props.rowStore.id,
                }
            }
        ).then(response => {
            if (response.data.result) {
                this.props.tableStore.actions.fetchByPage()

            } else {
                utils.handleNotifyExceptions(response)
            }
        }).catch(response => {
            this.isFetching = false;
            utils.handleNotifyExceptions(response)
        })
    }

    getLabel() {
        let {label = {}} = toJS(this.props.rowStore.row);
        return label.value || this.props.rowStore.id
    }

    render() {
        let showDelete = !this.props.rowStore.isSystem
            && !this.props.rowStore.isDefault
            && this.props.userStore.hasPerm("system");


        return (
            <ActionsComponent>
                {
                    showDelete && (
                        <DeleteAction
                            idLabel={this.getLabel()}
                            actionLabel={utils.getTranslation("Message.delete")}
                            deleteCallback={() => this.delete()}/>
                    )
                }
            </ActionsComponent>
        )
    }
}


class Page extends React.Component {
    constructor(props) {
        super(props);

        this.tableStore = new TableStore({
            labelCount: "Инвойсы", // лейбл около пагинации, по дефолту выводится "Количество: n"
            checkable: true, // включает функционал чекБоксов
            checkMulti: false, // можно ли зачекать много сразу или только один
            disableCount: true, // убрать отображение каунтера
            disablePagination: true, // убрать отображение пагинации
            autoRefresh: 5, // (секунды)  автообновление, 
            request: {
                // запрос грид с параметрами
                method: "RusInvoice.grid", 
                params: {},
                errorCallback: (responseData) => {

                }
            },
            // конструктор ячеек 
            cellConstructors: {
                error: flagCell
            },
            // конструктор филдов 
            fieldConstructors: {
                error_bit: flagCell
            },
            // callback на чек
            checkCallback: (ids) => {
                console.log(ids)
            },
            // callback на клик по строчке таблицы
            rowCallback: (rowStore) => {
                this.props.routerStore.router.navigate(ROUTES.rusInvoiceEdit, {id: rowStore.id})
            },
            ActionsComponent: TableActionsComponent // компонент действий
        });
    }

    render() {
        return (
            <Provider tableStore={this.tableStore}>
                <TableComponent/>
            </Provider>
        )
    }
}

SearchComponents

import SearchComponent, {SearchBox} from "@kaiju.ui/components/src/SearchComponent"

this.searchConf = {
    suggestionConf: {
        key: "q",
        request: {
            method: "Query.suggest",
            params: {
                business_unit: this.pageStore.mainFilters.business_unit || null,
            }
        },
        Component: Suggestions
    },
    disabled: this.pageStore.isFetching,
    callback: (query) => {
        this.pageStore.onQueryChange(query)
    }
};

<SearchComponent {...this.searchConf}/>

<SearchBox
    placeholder: "Поиск по идентификатору"
    callback={query => console.log("query", query)/>

Buttons

Simple button components:

  • Button - simple button
  • ButtonSuccess - success-style button
  • ButtonDefault - default-style button

More complex buttons:

  • ButtonDropdown
  • DoubleButtonDropdown

Simple button options

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |onClick or callback | function | the width of the carousel container. | undefined | Yes | |icon | string | icon near the button | none | No | |label | string | label of button | none | No | |className | string | custom css class. | none | No | |children | components | inner components | - | No | |disabled | bool | disable button clicks while requests | false | No | |style | css json | add custom style | - | No |

Complex button options

Options of parameter 'conf':

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |mainButtonConf | json of Button config | simple button conf | - | Yes | |dropDownConfs or items | array of button confs | [{label: ..., callback: ...}| none | No |

Example

import React from "react";
import ROUTES from "RoutingNames";

import {
Button,
ButtonSuccess,
ButtonDefault, 
ButtonDropdown, 
DoubleButtonDropdown 
} from "@kaiju.ui/components/src/Buttons";

class ExampleComp extends React.Component {

    constructor(props) {
        super(props);

        this.buttonConf = {
            label: utils.getTranslation("Button.create"),
            icon: "icon-plus",
            onClick: () => {
                this.props.routerStore.navigate(ROUTES.declarationAdd);
            }
        };
    }

    render() {
        return (
            <React.Fragment>
                // just point props directly into components
                <ButtonSuccess
                    label={"Открыть отчет"}
                    onClick={() => this.openReport()}
                />
                // all props from conf
                <ButtonDefault {...this.buttonConf}/>
            </React.Fragment>
        )
    }
}

class ExampleCompComplexBtns extends React.Component {

    constructor(props) {
        super(props);

        this.buttonDropdownConf = {
            mainButtonConf: {
                label: "Сохранить",
                // diff between dropdown conf and double button dropdown:
                // in double button you can path onclick event
                onClick: () => {
                    this.declarationStore.save();
                }
            },
            dropDownConfs: [
                {
                    label: "Report #1",
                    callback: () => this.openReport()
                },
                {
                    label: "Report #2",
                    callback: () => {
                        this.showDeleteWindow = true
                    }
                },
            ]
        };

        this.dropDownConf = {
            mainButtonConf: {
                label: "Настройки", // only label 
            },
            items: [
                {
                    label: "Report #1",
                    callback: () => {
                        console.log("test")
                    }
                },
                {
                    label: "Report #2",
                    callback: () => {
                        console.log("test")
                    }
                },
            ]
        };

    }

    render() {
        return (
            <React.Fragment>
                <ButtonDropdown conf={this.buttonDropdownConf}/>
                <DoubleButtonDropdown conf={...this.dropDownConf}/>
            </React.Fragment>
        )
    }
}

Header

Хедер на странице

Options

options of parameter 'conf':

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |dropdownConf or doubleButtonConf or buttonConf | button conf json| версия кнопки справа вверху |- | No | |settings | callback click function | иконка настройки | - | No | |label | string | лейбл | - | No | |searchCallback or searchConf| function or search conf | настройки поиска или функция на получение и обработку нового query | - | No | |breadcrumbs | breadcrumbs conf | хлебные крошки | - | No | |className | string | custom className | - | No |

Пример:

import Header from "@kaiju.ui/components/src/Header/base";

// с лейблом:
<Header
    breadcrumbs={this.breadcrumbs}
    className={"test-class-name"}
    label={"Грузы"}
/>

// c  поисковой строкой:
<Header
    breadcrumbs={breadcrumbs}
    buttonConf={buttonConf}
    searchConf={searchConf}
/>

Формат хлебных крошек:


this.breadcrumbs = [
    {
        label: "Page #1",
        path: "Link to page for router5js"
    },
    {
        label: "Page #2",
    },
];

Dynamic Header

Тот же хедер, но способный с помощью mobx изменять своё состояние

Options

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |isChanged | bool | показывает надпись "есть несохраненные изменения" | - | No | |isFetching | bool | блокирует кнопки| - | No |

example:

import {observer} from "mobx-react";
import ROUTES from "RoutingNames";
import DynamicHeader from "@kaiju.ui/components/src/Header";

DynamicHeader = observer(() => {
    this.breadcrumbs = [
        {
            label: "Декларации таможни",
            path: ROUTES.declarationAll
        },
        {
            label: "Редактирование",
        },
    ];

    let {mainFormStore, invoicesFormStore} = this.declarationStore;

    return (
        <DynamicHeader
            breadcrumbs={this.breadcrumbs}
            doubleButtonConf={this.buttonDropdownConf}
            isChanged={mainFormStore.isChanged || invoicesFormStore.isChanged}
            isFetching={mainFormStore.isFetching || invoicesFormStore.isFetching}
            label={mainFormStore.label}
        />
    )
});

Notifications

Notify alert in the right bottom of the screen:

  • notifyError - red error alert
  • notifySuccess - green success alert

Options

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |title | string| |- | no | |message | string | text message настройки | - | no | |delay | integer | time delay| error - 3000, success - 1000 msec | no |

import {notifyError, notifySuccess} from "@kaiju.ui/components/src/notifications";


notifyError("error", undefined, 300)
notifyError(null, "some message", 300)
notifySuccess("Done")

Tabs

Lib docs link --> ReactTabs

Main options

Все эти опции используются для того, чтобы сохранить состояне в session storage.

| option | type | description | default | required | |------------ |-----------|---------------------------------------|---------|-----------| |defaultIndex | integer| номер какой вкладки показывать по-умолчанию | 0 | no | |onSelect | function | получить новый индекс и сохранить его куда-нибудь| - | no |

Examples

Simple example:

import React from "react";
import {Tab, TabList, TabPanel, Tabs} from "@kaiju.ui/components/src/Tabs";
import Form from "@kaiju.ui/forms/src/Form";

export default class AttributeAddPage extends React.Component {

    render() {
        let {formStore} = this.formHandleStore;

        return (
            <React.Fragment>

                <Tabs className="page-content-body pl-5 pr-5"
                      defaultIndex={BaseStorage.getItem(this.props.route.name, 0)}
                      onSelect={(index) => BaseStorage.setItem(this.props.route.name, index)}>
                    <TabList>
                        <Tab>{utils.getTranslation("Tab.properties")}</Tab>
                    </TabList>

                    <TabPanel>
                        {
                            this.formHandleStore.dataInitialized &&
                            <div className={this.formHandleStore.isFetching ? "disabled-form mt-5" : " mt-5"}>
                                <Form key={formStore.key}
                                      store={formStore}
                                      groupFiltering/>
                            </div>
                        }
                    </TabPanel>

                </Tabs>
            </React.Fragment>
        )
    }
}

Dynamicly add tab:

import React from "react";
import ROUTES from "RoutingNames";
import {Tab, TabList, TabPanel, Tabs} from "@kaiju.ui/components/src/Tabs";
import Form from "@kaiju.ui/forms/src/Form";
import {observer} from "mobx-react";
import {observable} from "mobx";
import Axios from "axios";

@observer
export default class AttributeEditPage extends React.Component {
    @observable has_options = false;

    constructor(props) {
        super(props);
        // pass
    }

    componentDidMount() {
        this.checkIfOptionsEnabled()
    }

    checkIfOptionsEnabled() {
        // make request 
        Axios.post(ROUTES.rpc,
            {
                method: `${this.serviceName}.get`,
                params: {
                    engine: this.engineId,
                    key: this.attributeKey,
                    grouping: false
                }
            }
        ).then(response => {
            let result = response.data.result;

            // if attr has option mobX will rerender Tabs
            if (result) {
                this.has_options = result.kind === 'string'
            } else {
                utils.handleNotifyExceptions(response)
            }
        }).catch(response => {
            utils.handleNotifyExceptions(response)
        })
    };

    renderOptionsTable() {
        // pass
    }

    render() {
        let {formStore} = this.formHandleStore;


        const tabs = [
            <Tab key={utils.uuid4()}>{utils.getTranslation("Tab.properties")}</Tab>

        ];
        const tabPanels = [
            <TabPanel key={utils.uuid4()}>
                {
                    this.formHandleStore.dataInitialized &&
                    <div className={this.formHandleStore.isFetching ? "disabled-form mt-5" : " mt-5"}>
                        <Form key={formStore.key}
                              store={formStore}
                              groupFiltering/>
                    </div>
                }
            </TabPanel>
        ];

        if (this.has_options) {
            tabs.push(<Tab key={utils.uuid4()}>{utils.getTranslation("Label.options")}</Tab>);
            tabPanels.push(<TabPanel key={utils.uuid4()}>{this.renderOptionsTable()}</TabPanel>)
        }

        return (
            <React.Fragment>
                <Tabs className="attr-tabs__content_body pl-5 pr-5">
                    <TabList>{tabs}</TabList>
                    {tabPanels}
                </Tabs>
            </React.Fragment>
        )
    }
}

BaseStorage

Обертка от sessionStorage, чтобы хранить данные пользователя при сессии

BaseStorage.getItem("key")
BaseStorage.setItem("key", "some_value")
BaseStorage.setItem("key", {"count": 1})