@brandup/ui-kit 1.0.1 → 1.0.2

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
@@ -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
 
@@ -105,4 +105,33 @@ Styles for:
105
105
  - input[type=text]
106
106
  - textarea
107
107
 
108
- See [inputs.less](source/inputs.less) file.
108
+ See [inputs.less](source/inputs.less) file.
109
+
110
+ ### Popups
111
+
112
+ Popups work with class `ui-popup`.
113
+
114
+ ```HTML
115
+ <button data-command="ui-popup-toggle">Menu1</button>
116
+ <div class="ui-popup"></div>
117
+
118
+ <button id="menu2">Menu2</button>
119
+ <div id="popup2" class="ui-popup"></div>
120
+
121
+ <button>Menu3</button>
122
+ <div id="popup2" class="ui-popup"></div>
123
+ ```
124
+
125
+ Open popup by popup and initiator element:
126
+
127
+ ```TypeScript
128
+ PopupManager.open(DOM.getById("popup2"), { initiator: DOM.getById("menu2") });
129
+ ```
130
+
131
+ Open popup by only popup element:
132
+
133
+ ```TypeScript
134
+ PopupManager.open(DOM.getById("popup3"));
135
+ ```
136
+
137
+ If the initiator is specified, then when the popup is opened again, it will be closed.
package/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "type": "module",
24
24
  "license": "Apache-2.0",
25
- "version": "1.0.1",
25
+ "version": "1.0.2",
26
26
  "main": "source/index.ts",
27
27
  "types": "source/index.ts",
28
28
  "dependencies": {
@@ -31,6 +31,15 @@
31
31
  --svg-height: var(--svg-size);
32
32
  --svg-fill: var(--text-color);
33
33
  --svg-stroke: var(--text-color);
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 { Middleware } from "@brandup/ui-app";
1
+ import { UiKitMiddleware } from "./middleware";
2
+ export * from "./popup"
2
3
  import "./styles.less";
3
4
 
4
- export const uiKitMiddlewareFactory = (): Middleware => {
5
- return {
6
- name: "uikit"
7
- };
8
- };
5
+ export const uiKitMiddlewareFactory = () => new UiKitMiddleware();
@@ -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
+ }
@@ -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
+ }