@byndyusoft-ui/flex 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,108 @@
1
- # Temporary Holding Version
1
+ # `@byndyusoft-ui/flex`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ---
4
+
5
+ > Flex-раскладка поверх `@byndyusoft-ui/view`: фабрика `createFlex` создаёт компонент
6
+ > под набор значений отступов вашего проекта.
7
+
8
+ ## Установка
9
+
10
+ ```sh
11
+ npm i @byndyusoft-ui/flex
12
+ ```
13
+
14
+ ## Фабрика createFlex (свои значения отступов)
15
+
16
+ `createFlex` принимает компонент, созданный `createView` из `@byndyusoft-ui/view`, —
17
+ значения `values` и их типы выводятся из него, отдельно передавать их не нужно.
18
+ Изменили `values` в одном месте — типы и стили обоих компонентов обновились сами.
19
+
20
+ ```tsx
21
+ // src/shared/ui/layout.ts
22
+ import { createView } from '@byndyusoft-ui/view';
23
+ import { createFlex } from '@byndyusoft-ui/flex';
24
+
25
+ export const View = createView({
26
+ step: { value: 8, unit: 'px' },
27
+ values: { xs: 0.25, sm: 0.5, md: 1, lg: 1.5, xl: 2, xxl: 3 }
28
+ } as const);
29
+
30
+ export const Flex = createFlex(View);
31
+ ```
32
+
33
+ ```tsx
34
+ import { Flex, View } from '@/shared/ui/layout';
35
+
36
+ <Flex direction="column" gap="lg" p="xl">
37
+ <View mb="md">...</View>
38
+ <Flex gap="sm" alignItems="center">
39
+ ...
40
+ </Flex>
41
+ </Flex>;
42
+ ```
43
+
44
+ gap-пропсы принимают те же токены, что и spacing-пропсы View. Стили (классы отступов,
45
+ gap и flex-модификаторы) генерируются автоматически и доставляются так же, как у
46
+ `createView`: автоинъекция в браузере и компонент `ViewStylesInjector` для SSR — подробности
47
+ в README `@byndyusoft-ui/view`. Шаг `step` фиксируется при создании фабрики, а gap и отступы
48
+ выводятся готовыми CSS-длинами; дробные множители токенов поддерживаются. Flex наследует
49
+ `prefix` созданного View (по умолчанию `bsui`), поэтому его классы используют тот же namespace.
50
+ Flex поддерживает короткие aliases spacing-пропсов View
51
+ (`m`, `mt`, `mh`, `p`, `pt`, `ph` и остальные); правила приоритета, aliases и сокращения
52
+ классов описаны в README View.
53
+
54
+ Чтобы использовать отдельный namespace, задайте `prefix` в `createView`; он автоматически
55
+ применится и к классам Flex:
56
+
57
+ ```tsx
58
+ const View = createView({
59
+ step: { value: 1, unit: 'rem' },
60
+ prefix: 'app',
61
+ values: { sm: 0.5, md: 1 }
62
+ } as const);
63
+ const Flex = createFlex(View); // классы app-flex, app-flex--g-md и т.п.
64
+ ```
65
+
66
+ ## Props
67
+
68
+ | Проп | Тип | Описание |
69
+ | ---------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------- |
70
+ | `direction` | `row \| row-reverse \| column \| column-reverse` | `flex-direction` |
71
+ | `wrap` | `nowrap \| wrap \| wrap-reverse` | `flex-wrap` |
72
+ | `justifyContent` | `flex-start \| flex-end \| center \| space-between \| space-around \| space-evenly` | `justify-content` |
73
+ | `alignContent` | варианты выше + `stretch` | `align-content` |
74
+ | `alignItems` | `flex-start \| flex-end \| center \| baseline \| stretch` | `align-items` |
75
+ | `gap`, `rowGap`, `columnGap` | токен `values` | Отступы между элементами |
76
+ | spacing-пропсы View | токен `values` | Полные и короткие отступы |
77
+ | `ref` | `React.Ref<HTMLElement>` | Ref на host element созданного View |
78
+
79
+ `ref` указывает на тот же HTMLElement, который рендерит созданный View, в том числе при
80
+ переопределении тега через `as`:
81
+
82
+ ```tsx
83
+ import { useRef } from 'react';
84
+
85
+ const flexRef = useRef<HTMLElement>(null);
86
+ <Flex as="section" ref={flexRef} gap="md">
87
+ ...
88
+ </Flex>;
89
+ ```
90
+
91
+ Остальные пропсы (`as`, `className`, нативные атрибуты) проксируются в созданный View.
92
+
93
+ ## Утилиты и типы
94
+
95
+ Из точки входа пакета также доступны:
96
+
97
+ - `buildCss(config)` — генерация CSS для `gap`, `rowGap` и `columnGap`.
98
+ - `flexModifiersCss` — CSS базового класса и модификаторов раскладки.
99
+ - `blockClassName` — базовый класс `bsui-flex`.
100
+ - `getDirectionModifier`, `getWrapModifier`, `getAlignContentModifier`,
101
+ `getAlignItemsModifier`, `getJustifyContentModifier` — имена классов модификаторов;
102
+ без аргумента возвращают пустую строку.
103
+ - `directions`, `flexWraps`, `alignContentVariants`, `alignItemsVariants`,
104
+ `justifyContentVariants` — наборы допустимых значений, например для элементов управления.
105
+
106
+ Публичные типы: `ICreatedFlex`, `ICreatedFlexProps`, `TFlexDirection`, `TFlexWrap`,
107
+ `TAlignContent`, `TAlignItems` и `TJustifyContent`. Созданный компонент имеет
108
+ `displayName = 'Flex'` и хранит конфигурацию View в `Flex.config`.
@@ -0,0 +1,9 @@
1
+ export declare const blockClassName = "bsui-flex";
2
+ export declare function getFlexBlockClassName(classPrefix?: string): string;
3
+ export declare const directions: readonly ["row", "column", "row-reverse", "column-reverse"];
4
+ export declare const flexWraps: readonly ["nowrap", "wrap", "wrap-reverse"];
5
+ export declare const justifyContentVariants: readonly ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"];
6
+ export declare const alignContentVariants: readonly ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly", "stretch"];
7
+ export declare const alignItemsVariants: readonly ["flex-start", "flex-end", "center", "baseline", "stretch"];
8
+ export declare function buildFlexModifiersCss(classPrefix?: string): string;
9
+ export declare const flexModifiersCss: string;
@@ -0,0 +1,58 @@
1
+ const blockClassName = 'bsui-flex';
2
+ function getFlexBlockClassName(classPrefix = 'bsui') {
3
+ return `${classPrefix}-flex`;
4
+ }
5
+ const directions = ['row', 'column', 'row-reverse', 'column-reverse'];
6
+ const flexWraps = ['nowrap', 'wrap', 'wrap-reverse'];
7
+ const justifyContentVariants = [
8
+ 'flex-start',
9
+ 'flex-end',
10
+ 'center',
11
+ 'space-between',
12
+ 'space-around',
13
+ 'space-evenly'
14
+ ];
15
+ const alignContentVariants = [
16
+ 'flex-start',
17
+ 'flex-end',
18
+ 'center',
19
+ 'space-between',
20
+ 'space-around',
21
+ 'space-evenly',
22
+ 'stretch'
23
+ ];
24
+ const alignItemsVariants = ['flex-start', 'flex-end', 'center', 'baseline', 'stretch'];
25
+ function buildFlexModifiersCss(classPrefix = 'bsui') {
26
+ const flexClassName = getFlexBlockClassName(classPrefix);
27
+ return [
28
+ `.${flexClassName}{display:flex}`,
29
+ `.${flexClassName}--fd-row{flex-direction:row}`,
30
+ `.${flexClassName}--fd-row-reverse{flex-direction:row-reverse}`,
31
+ `.${flexClassName}--fd-column{flex-direction:column}`,
32
+ `.${flexClassName}--fd-column-reverse{flex-direction:column-reverse}`,
33
+ `.${flexClassName}--fw-nowrap{flex-wrap:nowrap}`,
34
+ `.${flexClassName}--fw-wrap{flex-wrap:wrap}`,
35
+ `.${flexClassName}--fw-wrap-reverse{flex-wrap:wrap-reverse}`,
36
+ `.${flexClassName}--jc-flex-start{justify-content:flex-start}`,
37
+ `.${flexClassName}--jc-flex-end{justify-content:flex-end}`,
38
+ `.${flexClassName}--jc-center{justify-content:center}`,
39
+ `.${flexClassName}--jc-space-between{justify-content:space-between}`,
40
+ `.${flexClassName}--jc-space-around{justify-content:space-around}`,
41
+ `.${flexClassName}--jc-space-evenly{justify-content:space-evenly}`,
42
+ `.${flexClassName}--ac-flex-start{align-content:flex-start}`,
43
+ `.${flexClassName}--ac-flex-end{align-content:flex-end}`,
44
+ `.${flexClassName}--ac-center{align-content:center}`,
45
+ `.${flexClassName}--ac-space-between{align-content:space-between}`,
46
+ `.${flexClassName}--ac-space-around{align-content:space-around}`,
47
+ `.${flexClassName}--ac-space-evenly{align-content:space-evenly}`,
48
+ `.${flexClassName}--ac-stretch{align-content:stretch}`,
49
+ `.${flexClassName}--ai-flex-start{align-items:flex-start}`,
50
+ `.${flexClassName}--ai-flex-end{align-items:flex-end}`,
51
+ `.${flexClassName}--ai-center{align-items:center}`,
52
+ `.${flexClassName}--ai-baseline{align-items:baseline}`,
53
+ `.${flexClassName}--ai-stretch{align-items:stretch}`
54
+ ].join('');
55
+ }
56
+ const flexModifiersCss = buildFlexModifiersCss();
57
+
58
+ export { alignContentVariants, alignItemsVariants, blockClassName, buildFlexModifiersCss, directions, flexModifiersCss, flexWraps, getFlexBlockClassName, justifyContentVariants };
@@ -0,0 +1,3 @@
1
+ import { type ICreatedView, type TSpacingValues } from '@byndyusoft-ui/view';
2
+ import type { ICreatedFlex } from './types';
3
+ export declare function createFlex<TValues extends TSpacingValues>(view: ICreatedView<TValues>): ICreatedFlex<TValues>;
@@ -0,0 +1,24 @@
1
+ import React, { forwardRef } from 'react';
2
+ import cn from 'classnames';
3
+ import { registerStyles } from '@byndyusoft-ui/view';
4
+ import { buildFlexModifiersCss, getFlexBlockClassName } from './constants.js';
5
+ import { buildCss } from './utilities/buildCss.js';
6
+ import { getAlignContentModifier } from './utilities/getAlignContentModifier.js';
7
+ import { getAlignItemsModifier } from './utilities/getAlignItemsModifier.js';
8
+ import { getDirectionModifier } from './utilities/getDirectionModifier.js';
9
+ import { getGapClassNames } from './utilities/getGapClassNames.js';
10
+ import { getJustifyContentModifier } from './utilities/getJustifyContentModifier.js';
11
+ import { getWrapModifier } from './utilities/getWrapModifier.js';
12
+
13
+ function createFlex(view) {
14
+ const classPrefix = view.config.prefix;
15
+ registerStyles(view.config, buildFlexModifiersCss(classPrefix) + buildCss(view.config));
16
+ const CreatedFlex = forwardRef(({ className, children, direction, wrap, alignContent, alignItems, justifyContent, gap, rowGap, columnGap, ...props }, ref) => {
17
+ const flexClassName = cn(getFlexBlockClassName(classPrefix), className, getDirectionModifier(direction, classPrefix), getWrapModifier(wrap, classPrefix), getAlignContentModifier(alignContent, classPrefix), getAlignItemsModifier(alignItems, classPrefix), getJustifyContentModifier(justifyContent, classPrefix), ...getGapClassNames(gap, rowGap, columnGap, classPrefix));
18
+ return React.createElement(view, { className: flexClassName, ...props, ref }, children);
19
+ });
20
+ CreatedFlex.displayName = 'Flex';
21
+ return Object.assign(CreatedFlex, { config: view.config });
22
+ }
23
+
24
+ export { createFlex };
@@ -0,0 +1,4 @@
1
+ export { createFlex } from './createFlex';
2
+ export { alignContentVariants, alignItemsVariants, blockClassName, directions, flexModifiersCss, flexWraps, justifyContentVariants } from './constants';
3
+ export { buildCss, getAlignContentModifier, getAlignItemsModifier, getDirectionModifier, getJustifyContentModifier, getWrapModifier } from './utilities';
4
+ export type { ICreatedFlex, ICreatedFlexProps, TAlignContent, TAlignItems, TFlexDirection, TFlexWrap, TJustifyContent } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { createFlex } from './createFlex.js';
2
+ export { alignContentVariants, alignItemsVariants, blockClassName, directions, flexModifiersCss, flexWraps, justifyContentVariants } from './constants.js';
3
+ export { buildCss } from './utilities/buildCss.js';
4
+ export { getAlignContentModifier } from './utilities/getAlignContentModifier.js';
5
+ export { getAlignItemsModifier } from './utilities/getAlignItemsModifier.js';
6
+ export { getDirectionModifier } from './utilities/getDirectionModifier.js';
7
+ export { getJustifyContentModifier } from './utilities/getJustifyContentModifier.js';
8
+ export { getWrapModifier } from './utilities/getWrapModifier.js';
@@ -0,0 +1,21 @@
1
+ import type { ForwardRefExoticComponent, RefAttributes } from 'react';
2
+ import type { ICreatedViewProps, IViewConfig, TSpacingValues, TValuesToken } from '@byndyusoft-ui/view';
3
+ import type { alignContentVariants, alignItemsVariants, directions, flexWraps, justifyContentVariants } from './constants';
4
+ export type TFlexDirection = (typeof directions)[number];
5
+ export type TFlexWrap = (typeof flexWraps)[number];
6
+ export type TJustifyContent = (typeof justifyContentVariants)[number];
7
+ export type TAlignContent = (typeof alignContentVariants)[number];
8
+ export type TAlignItems = (typeof alignItemsVariants)[number];
9
+ export interface ICreatedFlexProps<TValues extends TSpacingValues> extends ICreatedViewProps<TValues> {
10
+ alignContent?: TAlignContent;
11
+ alignItems?: TAlignItems;
12
+ direction?: TFlexDirection;
13
+ justifyContent?: TJustifyContent;
14
+ wrap?: TFlexWrap;
15
+ gap?: TValuesToken<TValues>;
16
+ rowGap?: TValuesToken<TValues>;
17
+ columnGap?: TValuesToken<TValues>;
18
+ }
19
+ export interface ICreatedFlex<TValues extends TSpacingValues> extends ForwardRefExoticComponent<ICreatedFlexProps<TValues> & RefAttributes<HTMLElement>> {
20
+ readonly config: IViewConfig<TValues>;
21
+ }
@@ -0,0 +1,2 @@
1
+ import { type IViewConfig, type TSpacingValues } from '@byndyusoft-ui/view';
2
+ export declare function buildCss<TValues extends TSpacingValues>(config: IViewConfig<TValues>): string;
@@ -0,0 +1,15 @@
1
+ import { getSpacingValue } from '@byndyusoft-ui/view';
2
+
3
+ function buildCss(config) {
4
+ const rules = [];
5
+ const blockClassName = `${config.prefix ?? 'bsui'}-flex`;
6
+ Object.entries(config.values).forEach(([token, multiplier]) => {
7
+ const value = getSpacingValue(config.step, multiplier);
8
+ rules.push(`.${blockClassName}--g-${token}{gap:${value}}`);
9
+ rules.push(`.${blockClassName}--rg-${token}{row-gap:${value}}`);
10
+ rules.push(`.${blockClassName}--cg-${token}{column-gap:${value}}`);
11
+ });
12
+ return rules.join('');
13
+ }
14
+
15
+ export { buildCss };
@@ -0,0 +1,2 @@
1
+ import type { TAlignContent } from '../types';
2
+ export declare function getAlignContentModifier(alignContent?: TAlignContent, classPrefix?: string): string;
@@ -0,0 +1,7 @@
1
+ import { getFlexBlockClassName } from '../constants.js';
2
+
3
+ function getAlignContentModifier(alignContent, classPrefix = 'bsui') {
4
+ return alignContent ? `${getFlexBlockClassName(classPrefix)}--ac-${alignContent}` : '';
5
+ }
6
+
7
+ export { getAlignContentModifier };
@@ -0,0 +1,2 @@
1
+ import type { TAlignItems } from '../types';
2
+ export declare function getAlignItemsModifier(alignItems?: TAlignItems, classPrefix?: string): string;
@@ -0,0 +1,7 @@
1
+ import { getFlexBlockClassName } from '../constants.js';
2
+
3
+ function getAlignItemsModifier(alignItems, classPrefix = 'bsui') {
4
+ return alignItems ? `${getFlexBlockClassName(classPrefix)}--ai-${alignItems}` : '';
5
+ }
6
+
7
+ export { getAlignItemsModifier };
@@ -0,0 +1,2 @@
1
+ import type { TFlexDirection } from '../types';
2
+ export declare function getDirectionModifier(direction?: TFlexDirection, classPrefix?: string): string;
@@ -0,0 +1,7 @@
1
+ import { getFlexBlockClassName } from '../constants.js';
2
+
3
+ function getDirectionModifier(direction, classPrefix = 'bsui') {
4
+ return direction ? `${getFlexBlockClassName(classPrefix)}--fd-${direction}` : '';
5
+ }
6
+
7
+ export { getDirectionModifier };
@@ -0,0 +1 @@
1
+ export declare function getGapClassNames(gap?: string, rowGap?: string, columnGap?: string, classPrefix?: string): Array<string>;
@@ -0,0 +1,19 @@
1
+ function getGapClassNames(gap, rowGap, columnGap, classPrefix = 'bsui') {
2
+ const blockClassName = `${classPrefix}-flex`;
3
+ if (gap) {
4
+ return [`${blockClassName}--g-${gap}`];
5
+ }
6
+ if (rowGap === columnGap && columnGap !== undefined) {
7
+ return [`${blockClassName}--g-${columnGap}`];
8
+ }
9
+ const classNames = [];
10
+ if (rowGap) {
11
+ classNames.push(`${blockClassName}--rg-${rowGap}`);
12
+ }
13
+ if (columnGap) {
14
+ classNames.push(`${blockClassName}--cg-${columnGap}`);
15
+ }
16
+ return classNames;
17
+ }
18
+
19
+ export { getGapClassNames };
@@ -0,0 +1,2 @@
1
+ import type { TJustifyContent } from '../types';
2
+ export declare function getJustifyContentModifier(justifyContent?: TJustifyContent, classPrefix?: string): string;
@@ -0,0 +1,7 @@
1
+ import { getFlexBlockClassName } from '../constants.js';
2
+
3
+ function getJustifyContentModifier(justifyContent, classPrefix = 'bsui') {
4
+ return justifyContent ? `${getFlexBlockClassName(classPrefix)}--jc-${justifyContent}` : '';
5
+ }
6
+
7
+ export { getJustifyContentModifier };
@@ -0,0 +1,2 @@
1
+ import type { TFlexWrap } from '../types';
2
+ export declare function getWrapModifier(wrap?: TFlexWrap, classPrefix?: string): string;
@@ -0,0 +1,7 @@
1
+ import { getFlexBlockClassName } from '../constants.js';
2
+
3
+ function getWrapModifier(wrap, classPrefix = 'bsui') {
4
+ return wrap ? `${getFlexBlockClassName(classPrefix)}--fw-${wrap}` : '';
5
+ }
6
+
7
+ export { getWrapModifier };
@@ -0,0 +1,7 @@
1
+ export { buildCss } from './buildCss';
2
+ export { getAlignContentModifier } from './getAlignContentModifier';
3
+ export { getAlignItemsModifier } from './getAlignItemsModifier';
4
+ export { getDirectionModifier } from './getDirectionModifier';
5
+ export { getGapClassNames } from './getGapClassNames';
6
+ export { getJustifyContentModifier } from './getJustifyContentModifier';
7
+ export { getWrapModifier } from './getWrapModifier';
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
2
  "name": "@byndyusoft-ui/flex",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "Byndyusoft UI Flex React Component",
5
+ "keywords": [
6
+ "byndyusoft",
7
+ "byndyusoft-ui",
8
+ "react",
9
+ "flex"
10
+ ],
11
+ "author": "Byndyusoft Frontend Developer <frontend@byndyusoft.com>",
12
+ "homepage": "https://github.com/Byndyusoft/ui/tree/master/components/flex#readme",
13
+ "license": "Apache-2.0",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "files": [
17
+ "dist/**/*"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/Byndyusoft/ui.git"
22
+ },
23
+ "scripts": {
24
+ "build": "rollup --config",
25
+ "clean": "rimraf dist && rimraf .turbo && rimraf node_modules && rimraf package-lock.json",
26
+ "lint:check": "npm run eslint:check && npm run prettier:check && npm run stylelint:check",
27
+ "lint:fix": "npm run eslint:fix && npm run prettier:fix && npm run stylelint:fix",
28
+ "eslint:check": "eslint src --config ../../eslint.config.js",
29
+ "eslint:fix": "eslint src --config ../../eslint.config.js --fix",
30
+ "prettier:check": "prettier --check \"**/*.{ts,tsx,css,scss,json}\"",
31
+ "prettier:fix": "prettier --write \"**/*.{ts,tsx,css,scss,json}\"",
32
+ "stylelint:check": "stylelint '**/*.{css,scss}' --allow-empty-input",
33
+ "stylelint:fix": "stylelint '**/*.{css,scss}' --fix --allow-empty-input",
34
+ "test": "vitest run --typecheck --root ../.. --exclude '**/.delta/**' components/flex/src"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/Byndyusoft/ui/issues"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "peerDependencies": {
43
+ "react": ">=17"
44
+ },
45
+ "dependencies": {
46
+ "@byndyusoft-ui/view": "^1.0.1",
47
+ "classnames": "^2.3.1"
48
+ }
49
+ }