@brandup/ui-kit 1.0.1 → 1.0.3
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 +37 -5
- package/package.json +1 -1
- package/source/common.less +35 -1
- package/source/index.ts +3 -6
- package/source/inputs.less +86 -10
- package/source/middleware.ts +23 -0
- package/source/popup.ts +79 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npm i @brandup/ui-kit@latest
|
|
|
10
10
|
|
|
11
11
|
Add `@brandup/ui-kit` middleware to your application.
|
|
12
12
|
|
|
13
|
-
```
|
|
13
|
+
```TypeScript
|
|
14
14
|
import { ApplicationBuilder } from "@brandup/ui-app";
|
|
15
15
|
import { uiKitMiddlewareFactory } from "@brandup/ui-kit";
|
|
16
16
|
|
|
@@ -101,8 +101,40 @@ See [common.less](source/common.less) file.
|
|
|
101
101
|
### Input styles
|
|
102
102
|
|
|
103
103
|
Styles for:
|
|
104
|
-
- reset for input, textarea, button
|
|
105
|
-
- input[type=text]
|
|
106
|
-
- textarea
|
|
107
104
|
|
|
108
|
-
|
|
105
|
+
- reset for input, textarea, button
|
|
106
|
+
- input[type=text]
|
|
107
|
+
- input[type=checkbox]
|
|
108
|
+
- textarea
|
|
109
|
+
- select
|
|
110
|
+
|
|
111
|
+
See [inputs.less](source/inputs.less) file.
|
|
112
|
+
|
|
113
|
+
### Popups
|
|
114
|
+
|
|
115
|
+
Popups work with class `ui-popup`.
|
|
116
|
+
|
|
117
|
+
```HTML
|
|
118
|
+
<button data-command="ui-popup-toggle">Menu1</button>
|
|
119
|
+
<div class="ui-popup"></div>
|
|
120
|
+
|
|
121
|
+
<button id="menu2">Menu2</button>
|
|
122
|
+
<div id="popup2" class="ui-popup"></div>
|
|
123
|
+
|
|
124
|
+
<button>Menu3</button>
|
|
125
|
+
<div id="popup2" class="ui-popup"></div>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Open popup by popup and initiator element:
|
|
129
|
+
|
|
130
|
+
```TypeScript
|
|
131
|
+
PopupManager.open(DOM.getById("popup2"), { initiator: DOM.getById("menu2") });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Open popup by only popup element:
|
|
135
|
+
|
|
136
|
+
```TypeScript
|
|
137
|
+
PopupManager.open(DOM.getById("popup3"));
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If the initiator is specified, then when the popup is opened again, it will be closed.
|
package/package.json
CHANGED
package/source/common.less
CHANGED
|
@@ -30,7 +30,16 @@
|
|
|
30
30
|
--svg-width: var(--svg-size);
|
|
31
31
|
--svg-height: var(--svg-size);
|
|
32
32
|
--svg-fill: var(--text-color);
|
|
33
|
-
--svg-stroke:
|
|
33
|
+
--svg-stroke: none;
|
|
34
|
+
|
|
35
|
+
// popup
|
|
36
|
+
|
|
37
|
+
--popup-fill: var(--main-background);
|
|
38
|
+
--popup-border-style: solid;
|
|
39
|
+
--popup-border-width: 1px;
|
|
40
|
+
--popup-border-color: #aaa;
|
|
41
|
+
--popup-border-radius: 5px;
|
|
42
|
+
--popup-box-shadow: 0px 4px 8px 2px rgba(0, 0, 0, 0.12);
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
// Body styles
|
|
@@ -105,4 +114,29 @@ svg {
|
|
|
105
114
|
padding-left: var(--content-padding-lr);
|
|
106
115
|
padding-right: var(--content-padding-lr);
|
|
107
116
|
box-sizing: border-box;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Popup styles
|
|
120
|
+
|
|
121
|
+
.ui-popup {
|
|
122
|
+
position: absolute;
|
|
123
|
+
box-sizing: border-box;
|
|
124
|
+
z-index: 1000;
|
|
125
|
+
background: var(--popup-fill);
|
|
126
|
+
border-style: var(--popup-border-style);
|
|
127
|
+
border-color: var(--popup-border-color);
|
|
128
|
+
border-width: var(--popup-border-width);
|
|
129
|
+
border-radius: var(--popup-border-radius);
|
|
130
|
+
box-shadow: var(--popup-box-shadow);
|
|
131
|
+
visibility: collapse;
|
|
132
|
+
|
|
133
|
+
&.opened {
|
|
134
|
+
visibility: visible;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.ui-popup-expanded {
|
|
139
|
+
& ~ .ui-popup {
|
|
140
|
+
visibility: visible;
|
|
141
|
+
}
|
|
108
142
|
}
|
package/source/index.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UiKitMiddleware } from "./middleware";
|
|
2
|
+
export * from "./popup"
|
|
2
3
|
import "./styles.less";
|
|
3
4
|
|
|
4
|
-
export const uiKitMiddlewareFactory = ()
|
|
5
|
-
return {
|
|
6
|
-
name: "uikit"
|
|
7
|
-
};
|
|
8
|
-
};
|
|
5
|
+
export const uiKitMiddlewareFactory = () => new UiKitMiddleware();
|
package/source/inputs.less
CHANGED
|
@@ -40,22 +40,30 @@
|
|
|
40
40
|
--invalid--input-border-color: red;
|
|
41
41
|
--invalid--input-fill: var(--input-fill);
|
|
42
42
|
--invalid--input-color: var(--input-color);
|
|
43
|
+
|
|
44
|
+
// toggler
|
|
45
|
+
--toggler-height: 30px;
|
|
46
|
+
--toggler-padding: 3px;
|
|
47
|
+
--toggler-round-fill: var(--hover--input-border-color); // цвет круглешка
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
input,
|
|
46
51
|
textarea,
|
|
47
|
-
button
|
|
48
|
-
|
|
52
|
+
button,
|
|
53
|
+
select {
|
|
49
54
|
font-family: inherit;
|
|
50
|
-
font-size:
|
|
55
|
+
font-size: var(--input-font-size);
|
|
56
|
+
font-weight: var(--input-font-weidth);
|
|
57
|
+
font-style: var(--input-font-style);
|
|
58
|
+
color: var(--input-color);
|
|
51
59
|
line-height: unset;
|
|
52
|
-
color: unset;
|
|
53
60
|
box-sizing: border-box;
|
|
54
61
|
padding: 0;
|
|
55
62
|
margin: 0;
|
|
56
63
|
}
|
|
57
64
|
|
|
58
|
-
input[type=text], textarea {
|
|
65
|
+
input[type=text], textarea, select {
|
|
66
|
+
appearance: none;
|
|
59
67
|
outline: none;
|
|
60
68
|
border-style: var(--input-border-type);
|
|
61
69
|
border-width: var(--input-border-width);
|
|
@@ -67,11 +75,6 @@ input[type=text], textarea {
|
|
|
67
75
|
padding-left: var(--input-padding-lr);
|
|
68
76
|
padding-right: var(--input-padding-lr);
|
|
69
77
|
|
|
70
|
-
font-size: var(--input-font-size);
|
|
71
|
-
font-weight: var(--input-font-weidth);
|
|
72
|
-
font-style: var(--input-font-style);
|
|
73
|
-
color: var(--input-color);
|
|
74
|
-
|
|
75
78
|
&::placeholder {
|
|
76
79
|
font-weight: var(--placeholder-font-weidth);
|
|
77
80
|
font-style: var(--placeholder-font-style);
|
|
@@ -101,7 +104,80 @@ input[type=text], textarea {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
|
|
107
|
+
select {
|
|
108
|
+
appearance: auto;
|
|
109
|
+
}
|
|
110
|
+
|
|
104
111
|
textarea {
|
|
105
112
|
padding-top: calc(1em / 2);
|
|
106
113
|
padding-bottom: calc(1em / 2);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
input[type=checkbox] {
|
|
117
|
+
appearance: none;
|
|
118
|
+
position: relative;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
|
|
121
|
+
background-color: var(--input-fill);
|
|
122
|
+
border-style: var(--input-border-type);
|
|
123
|
+
border-width: var(--input-border-width);
|
|
124
|
+
border-color: var(--input-border-color);
|
|
125
|
+
border-radius: calc(var(--toggler-height) / 2);
|
|
126
|
+
|
|
127
|
+
height: var(--toggler-height);
|
|
128
|
+
width: calc(var(--toggler-height) * 2);
|
|
129
|
+
|
|
130
|
+
--round-size: calc(var(--toggler-height) - var(--toggler-padding) * 2 - var(--input-border-width) * 2);
|
|
131
|
+
|
|
132
|
+
&:after {
|
|
133
|
+
content: '';
|
|
134
|
+
position: absolute;
|
|
135
|
+
background-color: var(--toggler-round-fill);
|
|
136
|
+
width: var(--round-size);
|
|
137
|
+
height: var(--round-size);
|
|
138
|
+
border-radius: 50%;
|
|
139
|
+
left: var(--toggler-padding);
|
|
140
|
+
margin-top: auto;
|
|
141
|
+
margin-bottom: auto;
|
|
142
|
+
top: 0;
|
|
143
|
+
bottom: 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
&:hover, &:focus {
|
|
147
|
+
border-color: var(--hover--input-border-color);
|
|
148
|
+
background: var(--hover--input-fill);
|
|
149
|
+
color: var(--hover--input-color);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
&[readonly] {
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
&:checked {
|
|
157
|
+
background-color: var(--toggler-round-fill);
|
|
158
|
+
|
|
159
|
+
&:after {
|
|
160
|
+
background-color: var(--input-fill);
|
|
161
|
+
right: var(--toggler-padding);
|
|
162
|
+
left: auto;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&:disabled {
|
|
167
|
+
border-color: var(--disabled--input-border-color);
|
|
168
|
+
background: var(--disabled--input-fill);
|
|
169
|
+
color: var(--disabled--input-color);
|
|
170
|
+
cursor: default;
|
|
171
|
+
|
|
172
|
+
&:after {
|
|
173
|
+
background-color: var(--toggler-round-fill);
|
|
174
|
+
opacity: 0.4;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
&:user-invalid {
|
|
179
|
+
border-color: var(--invalid--input-border-color);
|
|
180
|
+
background: var(--invalid--input-fill);
|
|
181
|
+
color: var(--invalid--input-color);
|
|
182
|
+
}
|
|
107
183
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Middleware, MiddlewareNext, NavigateContext, StartContext } from "@brandup/ui-app";
|
|
2
|
+
import { PopupManager, POPUP_COMMAND, POPUP_CLASS } from "./popup";
|
|
3
|
+
|
|
4
|
+
export class UiKitMiddleware implements Middleware {
|
|
5
|
+
name = "uikit";
|
|
6
|
+
|
|
7
|
+
start(context: StartContext, next: MiddlewareNext) {
|
|
8
|
+
context.app.registerCommand(POPUP_COMMAND, context => {
|
|
9
|
+
if (!context.target.nextElementSibling?.classList.contains(POPUP_CLASS))
|
|
10
|
+
throw new Error('Not found popup elem.');
|
|
11
|
+
|
|
12
|
+
PopupManager.open(context.target.nextElementSibling as HTMLElement, { initiator: context.target });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return next();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
navigate(_context: NavigateContext, next: MiddlewareNext) {
|
|
19
|
+
PopupManager.close(); // закрываем открытое контекстное меню при навигации
|
|
20
|
+
|
|
21
|
+
return next();
|
|
22
|
+
}
|
|
23
|
+
}
|
package/source/popup.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export const POPUP_CLASS = "ui-popup";
|
|
2
|
+
export const POPUP_EXPANDED_CLASS = "ui-popup-expanded";
|
|
3
|
+
export const POPUP_COMMAND = "ui-popup-toggle";
|
|
4
|
+
|
|
5
|
+
type CurrentPopup = {
|
|
6
|
+
initiator?: HTMLElement,
|
|
7
|
+
popup: HTMLElement,
|
|
8
|
+
closeCallback?: () => void
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
var current: CurrentPopup | null = null;
|
|
12
|
+
|
|
13
|
+
const closePopupEventHandler = (e: MouseEvent) => {
|
|
14
|
+
const target = e.target as HTMLElement;
|
|
15
|
+
if (target.closest(`.${POPUP_CLASS}`))
|
|
16
|
+
return; // если клик внутри popup, то делать ничего не нужно
|
|
17
|
+
|
|
18
|
+
close();
|
|
19
|
+
|
|
20
|
+
const clickedMenuItem = target.closest(`.${POPUP_EXPANDED_CLASS}`);
|
|
21
|
+
if (clickedMenuItem || target == current?.initiator) {
|
|
22
|
+
// если клик по тому же элементу, который открыл контекстное меню, то останавливаем обработку клика, чтобы оно не отрылось заново
|
|
23
|
+
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
e.stopImmediatePropagation();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const close = () => {
|
|
30
|
+
if (current) {
|
|
31
|
+
if (current.closeCallback)
|
|
32
|
+
current.closeCallback();
|
|
33
|
+
|
|
34
|
+
current.initiator?.classList.remove(POPUP_EXPANDED_CLASS); // закрываем последнее открытое контекстное меню
|
|
35
|
+
current.popup.classList.remove("opened");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
document.body.removeEventListener("click", closePopupEventHandler);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const open = (popupElem: HTMLElement, options?: PopupOptions) => {
|
|
42
|
+
let newPopup: CurrentPopup = {
|
|
43
|
+
popup: popupElem,
|
|
44
|
+
initiator: options?.initiator
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
newPopup.closeCallback = options?.onClose;
|
|
48
|
+
|
|
49
|
+
if (newPopup.popup.classList.toggle("opened")) {
|
|
50
|
+
// это новый popup, открываем его
|
|
51
|
+
|
|
52
|
+
newPopup.initiator?.classList.add(POPUP_EXPANDED_CLASS);
|
|
53
|
+
|
|
54
|
+
document.body.addEventListener("click", closePopupEventHandler);
|
|
55
|
+
|
|
56
|
+
current = newPopup;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// данный popup уже открыт, закрываем его
|
|
60
|
+
close();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const PopupManager: IPopupManager = {
|
|
65
|
+
open,
|
|
66
|
+
close,
|
|
67
|
+
isOpened: () => !!current
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
interface IPopupManager {
|
|
71
|
+
open: (popupElem: HTMLElement, options?: PopupOptions) => void;
|
|
72
|
+
close: () => void;
|
|
73
|
+
isOpened: () => boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface PopupOptions {
|
|
77
|
+
initiator?: HTMLElement;
|
|
78
|
+
onClose?: () => void
|
|
79
|
+
}
|