# @kaiju.ui/components

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

Latest version **2.5.3** (published 2024-05-24) · ISC license · 0 weekly downloads

## Install

```sh
npm install @kaiju.ui/components
pnpm add @kaiju.ui/components
yarn add @kaiju.ui/components
bun add @kaiju.ui/components
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.5.3 |
| Published | 2024-05-24 |
| First published | 2020-06-10 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 14 |
| Unpacked size | 333.6 KB |
| Known vulnerabilities | 0 (+25 in 1 direct dependencies) |
| Install scripts | no |
| Author | Alexey Savchenko and Sargsyan Sergey |
| Maintainers | poplavskiy-a, beastrock, xmachin, mishdrob, dardivil |

## Links

- npm: https://www.npmjs.com/package/@kaiju.ui/components
- Repository: https://gitlab.com:kaiju-ui/kaiju.ui.components
- Homepage: https://gitlab.com/kaiju-ui/kaiju.ui.components/-/blob/master/README.md
- npm.io page: https://npm.io/package/@kaiju.ui/components

## Dependencies (14)

- [mobx](https://npm.io/package/mobx.md) ^5.15.0
- [axios](https://npm.io/package/axios.md) ^0.19.0
- [react](https://npm.io/package/react.md) ^16.13.1
- [react-dom](https://npm.io/package/react-dom.md) ^16.13.1
- [array-move](https://npm.io/package/array-move.md) ^2.2.1
- [mobx-react](https://npm.io/package/mobx-react.md) ^6.1.4
- [react-tabs](https://npm.io/package/react-tabs.md) ^3.1.1
- [react-helmet](https://npm.io/package/react-helmet.md) ^6.1.0
- [react-select](https://npm.io/package/react-select.md) ^3.0.26
- [react-tooltip](https://npm.io/package/react-tooltip.md) ^3.11.1
- [react-json-view](https://npm.io/package/react-json-view.md) 1.21.3
- [react-sortable-hoc](https://npm.io/package/react-sortable-hoc.md) ^1.10.1
- [styled-notifications](https://npm.io/package/styled-notifications.md) ^1.0.3
- [react-select-async-paginate](https://npm.io/package/react-select-async-paginate.md) ^0.4.1

## Recent versions

- 2.5.3 (latest) — 2024-05-24
- 2.5.2 — 2023-10-19
- 2.5.1 — 2023-09-04
- 2.5.0 — 2023-07-21
- 2.4.9 — 2023-04-12
- 2.4.8 — 2023-04-11
- 2.4.7 — 2023-03-14
- 2.4.6 — 2023-03-14
- 2.4.5 — 2022-12-08
- 2.4.4 — 2022-12-08
- 2.4.3 — 2022-12-08
- 2.4.1 — 2022-12-08
- 2.4.0 — 2022-11-29
- 2.3.9 — 2022-07-11
- 2.3.8 — 2022-07-11
- … 174 more at https://npm.io/package/@kaiju.ui/components/versions

## 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

```javascript
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:  
```javascript
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

```javascript
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

```javascript
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   |

Пример:
```javascript
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}
/>

```

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

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:  
```javascript
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   |
 
```javascript
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](https://github.com/reactjs/react-tabs)

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

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

## Examples

Simple example:
```javascript
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:
```javascript
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, чтобы хранить данные пользователя при сессии
```javascript
BaseStorage.getItem("key")
BaseStorage.setItem("key", "some_value")
BaseStorage.setItem("key", {"count": 1})
```

---
_Source: https://npm.io/package/@kaiju.ui/components · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
