@brandup/ui-kit 1.0.26 → 1.0.28
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 +114 -135
- package/build/parse-less-vars.cjs +5 -6
- package/package.json +2 -2
- package/source/index.ts +2 -2
- package/source/middleware.ts +3 -3
- package/source/popup.ts +16 -17
- package/source/utils/compatibility.ts +3 -1
package/README.md
CHANGED
|
@@ -1,200 +1,179 @@
|
|
|
1
|
-
# brandup
|
|
1
|
+
# @brandup/ui-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://dev.azure.com/brandup/BrandUp%20Core/_build/latest?definitionId=81&branchName=main)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Базовый пакет UI-кита: сброс стилей, типографика, стили полей ввода, PopupManager и middleware для `@brandup/ui-app`.
|
|
6
|
+
|
|
7
|
+
## Установка
|
|
6
8
|
|
|
7
9
|
```
|
|
8
|
-
npm i @brandup/ui-kit
|
|
10
|
+
npm i @brandup/ui-kit
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
## Подключение middleware
|
|
14
|
+
|
|
15
|
+
Зарегистрируйте `uiKitMiddlewareFactory` в сборщике приложения. Middleware автоматически регистрирует команду `ui-popup-toggle` для управления попапами.
|
|
12
16
|
|
|
13
|
-
```
|
|
17
|
+
```typescript
|
|
14
18
|
import { ApplicationBuilder } from "@brandup/ui-app";
|
|
15
19
|
import { uiKitMiddlewareFactory } from "@brandup/ui-kit";
|
|
16
20
|
|
|
17
21
|
const builder = new ApplicationBuilder({});
|
|
18
|
-
builder
|
|
19
|
-
.useMiddleware(uiKitMiddlewareFactory)
|
|
20
|
-
.useMiddleware(... other middleware);
|
|
22
|
+
builder.useMiddleware(uiKitMiddlewareFactory);
|
|
21
23
|
|
|
22
24
|
const app = builder.build({ basePath: "/" });
|
|
23
|
-
|
|
24
25
|
app.run();
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
-
|
|
29
|
-
### Reset styles
|
|
30
|
-
|
|
31
|
-
Reset styles for `<ul>`, `<ol>`, `<menu>`, `<img>` and others.
|
|
32
|
-
|
|
33
|
-
See [reset.less](source/reset.less) file.
|
|
34
|
-
|
|
35
|
-
### Body styles
|
|
36
|
-
|
|
37
|
-
Default root styles for `<body>` tag.
|
|
28
|
+
## PopupManager
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
--main-background
|
|
41
|
-
--font-size
|
|
42
|
-
--font-family
|
|
43
|
-
--font-weight
|
|
44
|
-
--line-height
|
|
45
|
-
--text-color
|
|
46
|
-
```
|
|
30
|
+
Статический менеджер для управления всплывающими панелями. В каждый момент времени открыт не более одного попапа.
|
|
47
31
|
|
|
48
|
-
|
|
32
|
+
### Разметка
|
|
49
33
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Default root styles for `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`.
|
|
34
|
+
Добавьте CSS-класс `ui-popup` на элемент попапа.
|
|
53
35
|
|
|
36
|
+
```html
|
|
37
|
+
<!-- Кнопка-инициатор рядом с попапом — команда ui-popup-toggle регистрируется middleware -->
|
|
38
|
+
<button data-command="ui-popup-toggle">Меню</button>
|
|
39
|
+
<div class="ui-popup">...</div>
|
|
54
40
|
```
|
|
55
|
-
--h-line-height
|
|
56
|
-
|
|
57
|
-
--h1-font-size
|
|
58
|
-
--h1-font-weidth
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
--h2-font-weidth
|
|
62
|
-
|
|
63
|
-
--h3-font-size
|
|
64
|
-
--h3-font-weidth
|
|
65
|
-
|
|
66
|
-
--h4-font-size
|
|
67
|
-
--h4-font-weidth
|
|
68
|
-
|
|
69
|
-
--h5-font-size
|
|
70
|
-
--h5-font-weidth
|
|
71
|
-
```
|
|
42
|
+
### API
|
|
72
43
|
|
|
73
|
-
|
|
44
|
+
```typescript
|
|
45
|
+
import { PopupManager } from "@brandup/ui-kit";
|
|
74
46
|
|
|
75
|
-
|
|
47
|
+
// Открыть попап (закрывает предыдущий, если был открыт другой)
|
|
48
|
+
PopupManager.open(popupElem, {
|
|
49
|
+
initiator: buttonElem, // необязательно: повторный клик по initiator закроет попап
|
|
50
|
+
onClose: () => { }, // необязательно: callback при закрытии
|
|
51
|
+
});
|
|
76
52
|
|
|
77
|
-
|
|
53
|
+
// Закрыть текущий попап
|
|
54
|
+
PopupManager.close();
|
|
78
55
|
|
|
56
|
+
// Проверить, открыт ли какой-либо попап
|
|
57
|
+
PopupManager.isOpened(); // boolean
|
|
79
58
|
```
|
|
80
|
-
--svg-size: 20px;
|
|
81
|
-
--svg-fill: var(--text-color);
|
|
82
|
-
--svg-stroke: none;
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
See [common.less](source/common.less) file.
|
|
86
59
|
|
|
87
|
-
|
|
60
|
+
## Утилиты
|
|
88
61
|
|
|
89
|
-
|
|
62
|
+
```typescript
|
|
63
|
+
import { IS_TOUCH_DEVICE } from "@brandup/ui-kit";
|
|
90
64
|
|
|
65
|
+
// true на touch-устройствах (мобильные, планшеты)
|
|
66
|
+
if (IS_TOUCH_DEVICE) { ... }
|
|
91
67
|
```
|
|
92
|
-
--content-max-width
|
|
93
|
-
--content-min-width
|
|
94
|
-
--content-padding-lr
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
See [common.less](source/common.less) file.
|
|
98
68
|
|
|
99
|
-
|
|
69
|
+
## Стили
|
|
100
70
|
|
|
101
|
-
|
|
71
|
+
Подключите стили через импорт в точке входа — они включаются автоматически вместе с пакетом.
|
|
102
72
|
|
|
103
|
-
|
|
104
|
-
- input[type=text]
|
|
105
|
-
- input[type=tel]
|
|
106
|
-
- input[type=email]
|
|
107
|
-
- input[type=password]
|
|
108
|
-
- input[type=search]
|
|
109
|
-
- input[type=url]
|
|
110
|
-
- input[type=date]
|
|
111
|
-
- input[type=datetime]
|
|
112
|
-
- input[type=datetime-local]
|
|
113
|
-
- input[type=time]
|
|
114
|
-
- input[type=file]
|
|
115
|
-
- input[type=number]
|
|
116
|
-
- input[type=checkbox]
|
|
117
|
-
- textarea
|
|
118
|
-
- select
|
|
73
|
+
### Переменные Less
|
|
119
74
|
|
|
120
|
-
|
|
75
|
+
Переопределите значения в файле `uikit.vars.less` в корне проекта перед сборкой. Файл с переменными по умолчанию: [vars.less](vars.less).
|
|
121
76
|
|
|
122
|
-
|
|
77
|
+
**Адаптивные брейкпоинты:**
|
|
123
78
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
79
|
+
```less
|
|
80
|
+
@adaptive-desktop-small: 1650px;
|
|
81
|
+
@adaptive-notebook: 1550px;
|
|
82
|
+
@adaptive-notebook-small: 1370px;
|
|
83
|
+
@adaptive-tablet: 1030px;
|
|
84
|
+
@adaptive-tablet-small: 850px;
|
|
85
|
+
@adaptive-mobile: 500px;
|
|
86
|
+
@adaptive-mobile-small: 370px;
|
|
87
|
+
```
|
|
129
88
|
|
|
130
|
-
|
|
131
|
-
<div id="popup2" class="ui-popup"></div>
|
|
89
|
+
**Общие:**
|
|
132
90
|
|
|
133
|
-
|
|
134
|
-
|
|
91
|
+
```less
|
|
92
|
+
@main-background: #fff;
|
|
93
|
+
@font-size: 14px;
|
|
94
|
+
@font-family: system-ui, ...;
|
|
95
|
+
@font-weight: 400;
|
|
96
|
+
@line-height: 130%;
|
|
97
|
+
@text-color: #222;
|
|
135
98
|
```
|
|
136
99
|
|
|
137
|
-
|
|
100
|
+
**Заголовки (`h1`–`h5`):**
|
|
138
101
|
|
|
139
|
-
```
|
|
140
|
-
|
|
102
|
+
```less
|
|
103
|
+
@h-line-height: 130%;
|
|
104
|
+
@h1-font-size: 56px; @h1-font-weight: 600;
|
|
105
|
+
@h2-font-size: 50px; @h2-font-weight: 600;
|
|
106
|
+
@h3-font-size: 28px; @h3-font-weight: 600;
|
|
107
|
+
@h4-font-size: 22px; @h4-font-weight: 600;
|
|
108
|
+
@h5-font-size: 18px; @h5-font-weight: 600;
|
|
141
109
|
```
|
|
142
110
|
|
|
143
|
-
|
|
111
|
+
**SVG:**
|
|
144
112
|
|
|
145
|
-
```
|
|
146
|
-
|
|
113
|
+
```less
|
|
114
|
+
@svg-size: 20px;
|
|
115
|
+
@svg-fill: @text-color;
|
|
116
|
+
@svg-stroke: none;
|
|
147
117
|
```
|
|
148
118
|
|
|
149
|
-
|
|
119
|
+
**Блок контента (класс `content-width`):**
|
|
150
120
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
121
|
+
```less
|
|
122
|
+
@content-max-width: 1280px;
|
|
123
|
+
@content-min-width: 320px;
|
|
124
|
+
@content-padding-lr: 40px;
|
|
125
|
+
```
|
|
154
126
|
|
|
155
|
-
|
|
127
|
+
**Попапы:**
|
|
156
128
|
|
|
157
|
-
```
|
|
158
|
-
|
|
129
|
+
```less
|
|
130
|
+
@popup-fill: @main-background;
|
|
131
|
+
@popup-color: @text-color;
|
|
132
|
+
@popup-border-radius: 5px;
|
|
133
|
+
@popup-box-shadow: 0px 4px 8px 2px rgba(0,0,0,0.12);
|
|
159
134
|
```
|
|
160
135
|
|
|
161
|
-
|
|
136
|
+
**Поля ввода:**
|
|
162
137
|
|
|
163
|
-
|
|
138
|
+
```less
|
|
139
|
+
@input-height: 46px;
|
|
140
|
+
@input-padding-lr: 20px;
|
|
141
|
+
@input-fill: #fff;
|
|
142
|
+
@input-color: @text-color;
|
|
143
|
+
@input-font-size: 14px;
|
|
164
144
|
|
|
165
|
-
|
|
166
|
-
|
|
145
|
+
// Состояния: hover, focus, readonly, disabled, invalid, incorrect
|
|
146
|
+
@hover--input-border-color: #666;
|
|
147
|
+
@focus--input-border-color: #222;
|
|
148
|
+
@readonly--input-fill: #f7f7f7;
|
|
149
|
+
@disabled--input-fill: #eee;
|
|
150
|
+
@invalid--input-border-color: red;
|
|
151
|
+
```
|
|
167
152
|
|
|
168
|
-
|
|
153
|
+
### parseLessVars
|
|
169
154
|
|
|
170
|
-
|
|
171
|
-
@main-color: #ff0000;
|
|
172
|
-
@secondary-color: rgba(0, 0, 0, 0.5);
|
|
173
|
-
@font-size: 16px;
|
|
174
|
-
```
|
|
155
|
+
Утилита для чтения Less-переменных в конфигурации webpack.
|
|
175
156
|
|
|
176
|
-
|
|
157
|
+
```js
|
|
158
|
+
const parseLessVars = require("@brandup/ui-kit/build/parse-less-vars.cjs");
|
|
177
159
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
'@main-color': '#ff0000',
|
|
181
|
-
'@secondary-color': 'rgba(0,0,0,0.5)',
|
|
182
|
-
'@font-size': '16px'
|
|
183
|
-
}
|
|
184
|
-
```
|
|
160
|
+
// Читает uikit.vars.less из корня проекта
|
|
161
|
+
const vars = parseLessVars();
|
|
185
162
|
|
|
186
|
-
|
|
187
|
-
const
|
|
163
|
+
// Или явно указать путь к файлу
|
|
164
|
+
const vars = parseLessVars("path/to/variables.less");
|
|
165
|
+
// { '@main-color': '#ff0000', '@font-size': '16px', ... }
|
|
188
166
|
```
|
|
189
167
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
Usage in the less-loader configuration.
|
|
168
|
+
Использование в конфигурации `less-loader`:
|
|
193
169
|
|
|
194
|
-
```
|
|
170
|
+
```js
|
|
195
171
|
{
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
172
|
+
loader: "less-loader",
|
|
173
|
+
options: {
|
|
174
|
+
lessOptions: {
|
|
175
|
+
modifyVars: parseLessVars(),
|
|
176
|
+
},
|
|
177
|
+
},
|
|
199
178
|
}
|
|
200
179
|
```
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
|
|
3
3
|
function parseLessVars(filePath) {
|
|
4
|
-
filePath = filePath ??
|
|
5
|
-
if (!fs.existsSync(filePath))
|
|
6
|
-
throw new Error("Not found UI kit configuration file uikit.vars.less.");
|
|
4
|
+
filePath = filePath ?? "uikit.vars.less";
|
|
5
|
+
if (!fs.existsSync(filePath)) throw new Error("Not found UI kit configuration file uikit.vars.less.");
|
|
7
6
|
|
|
8
|
-
const content = fs.readFileSync(filePath,
|
|
7
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
9
8
|
|
|
10
9
|
let variables = {};
|
|
11
10
|
|
|
12
|
-
content.split(
|
|
11
|
+
content.split("\n").forEach((line) => {
|
|
13
12
|
const match = line.match(/@([\w-]+)\s*:\s*(.+);/);
|
|
14
13
|
if (match) variables[`@${match[1]}`] = match[2].trim();
|
|
15
14
|
});
|
|
16
15
|
return variables;
|
|
17
16
|
}
|
|
18
|
-
module.exports = parseLessVars;
|
|
17
|
+
module.exports = parseLessVars;
|
package/package.json
CHANGED
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"type": "module",
|
|
24
24
|
"license": "Apache-2.0",
|
|
25
|
-
"version": "1.0.
|
|
25
|
+
"version": "1.0.28",
|
|
26
26
|
"main": "source/index.ts",
|
|
27
27
|
"types": "source/index.ts",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@brandup/ui-app": "^
|
|
29
|
+
"@brandup/ui-app": "^2.0.2"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"source",
|
package/source/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UiKitMiddleware } from "./middleware";
|
|
2
|
-
export * from "./popup"
|
|
2
|
+
export * from "./popup";
|
|
3
3
|
export { IS_TOUCH_DEVICE } from "./utils/compatibility";
|
|
4
4
|
import "./styles.less";
|
|
5
5
|
|
|
6
|
-
export const uiKitMiddlewareFactory = () => new UiKitMiddleware();
|
|
6
|
+
export const uiKitMiddlewareFactory = () => new UiKitMiddleware();
|
package/source/middleware.ts
CHANGED
|
@@ -5,9 +5,9 @@ export class UiKitMiddleware implements Middleware {
|
|
|
5
5
|
name = "uikit";
|
|
6
6
|
|
|
7
7
|
start(context: StartContext, next: MiddlewareNext) {
|
|
8
|
-
context.app.registerCommand(POPUP_COMMAND, context => {
|
|
8
|
+
context.app.registerCommand(POPUP_COMMAND, (context) => {
|
|
9
9
|
if (!context.target.nextElementSibling?.classList.contains(POPUP_CLASS))
|
|
10
|
-
throw new Error(
|
|
10
|
+
throw new Error("Not found popup elem.");
|
|
11
11
|
|
|
12
12
|
PopupManager.open(context.target.nextElementSibling as HTMLElement, { initiator: context.target });
|
|
13
13
|
});
|
|
@@ -20,4 +20,4 @@ export class UiKitMiddleware implements Middleware {
|
|
|
20
20
|
|
|
21
21
|
return next();
|
|
22
22
|
}
|
|
23
|
-
}
|
|
23
|
+
}
|
package/source/popup.ts
CHANGED
|
@@ -3,17 +3,16 @@ export const POPUP_EXPANDED_CLASS = "ui-popup-expanded";
|
|
|
3
3
|
export const POPUP_COMMAND = "ui-popup-toggle";
|
|
4
4
|
|
|
5
5
|
type CurrentPopup = {
|
|
6
|
-
initiator?: HTMLElement
|
|
7
|
-
popup: HTMLElement
|
|
8
|
-
closeCallback?: () => void
|
|
6
|
+
initiator?: HTMLElement;
|
|
7
|
+
popup: HTMLElement;
|
|
8
|
+
closeCallback?: () => void;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
let current: CurrentPopup | null = null;
|
|
12
12
|
|
|
13
13
|
const closePopupEventHandler = (e: MouseEvent) => {
|
|
14
14
|
const target = e.target as HTMLElement;
|
|
15
|
-
if (target.closest(`.${POPUP_CLASS}`))
|
|
16
|
-
return; // если клик внутри popup, то делать ничего не нужно
|
|
15
|
+
if (target.closest(`.${POPUP_CLASS}`)) return; // если клик внутри popup, то делать ничего не нужно
|
|
17
16
|
|
|
18
17
|
const clickedMenuItem = target.closest(`.${POPUP_EXPANDED_CLASS}`);
|
|
19
18
|
const isInitiator = target == current?.initiator;
|
|
@@ -30,8 +29,7 @@ const closePopupEventHandler = (e: MouseEvent) => {
|
|
|
30
29
|
|
|
31
30
|
const close = () => {
|
|
32
31
|
if (current) {
|
|
33
|
-
if (current.closeCallback)
|
|
34
|
-
current.closeCallback();
|
|
32
|
+
if (current.closeCallback) current.closeCallback();
|
|
35
33
|
|
|
36
34
|
current.initiator?.classList.remove(POPUP_EXPANDED_CLASS); // закрываем последнее открытое контекстное меню
|
|
37
35
|
current.popup.classList.remove("opened");
|
|
@@ -40,12 +38,14 @@ const close = () => {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
document.body.removeEventListener("click", closePopupEventHandler);
|
|
43
|
-
}
|
|
41
|
+
};
|
|
44
42
|
|
|
45
43
|
const open = (popupElem: HTMLElement, options?: PopupOptions) => {
|
|
46
|
-
|
|
44
|
+
if (current && current.popup !== popupElem) close(); // если открыт другой popup, закрываем его, чтобы не оставлять «осиротевший» visible popup
|
|
45
|
+
|
|
46
|
+
const newPopup: CurrentPopup = {
|
|
47
47
|
popup: popupElem,
|
|
48
|
-
initiator: options?.initiator
|
|
48
|
+
initiator: options?.initiator,
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
newPopup.closeCallback = options?.onClose;
|
|
@@ -58,17 +58,16 @@ const open = (popupElem: HTMLElement, options?: PopupOptions) => {
|
|
|
58
58
|
document.body.addEventListener("click", closePopupEventHandler);
|
|
59
59
|
|
|
60
60
|
current = newPopup;
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
61
|
+
} else {
|
|
63
62
|
// данный popup уже открыт, закрываем его
|
|
64
63
|
close();
|
|
65
64
|
}
|
|
66
|
-
}
|
|
65
|
+
};
|
|
67
66
|
|
|
68
67
|
export const PopupManager: IPopupManager = {
|
|
69
68
|
open,
|
|
70
69
|
close,
|
|
71
|
-
isOpened: () => !!current
|
|
70
|
+
isOpened: () => !!current,
|
|
72
71
|
};
|
|
73
72
|
|
|
74
73
|
interface IPopupManager {
|
|
@@ -79,5 +78,5 @@ interface IPopupManager {
|
|
|
79
78
|
|
|
80
79
|
interface PopupOptions {
|
|
81
80
|
initiator?: HTMLElement;
|
|
82
|
-
onClose?: () => void
|
|
83
|
-
}
|
|
81
|
+
onClose?: () => void;
|
|
82
|
+
}
|