@neovici/cosmoz-bottom-bar 7.2.0 → 7.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-bottom-bar",
3
- "version": "7.2.0",
3
+ "version": "7.2.1",
4
4
  "description": "A responsive bottom-bar that can house buttons/actions and a menu for the buttons that won't fit the available width.",
5
5
  "keywords": [
6
6
  "polymer",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "files": [
28
28
  "cosmoz-*.js",
29
- "lib/**/*.js"
29
+ "src/**/*.js"
30
30
  ],
31
31
  "scripts": {
32
32
  "lint": "eslint --cache --ext .js .",
@@ -0,0 +1,208 @@
1
+ /* eslint-disable max-len */
2
+ /* eslint-disable max-lines */
3
+ import { html } from 'lit-html';
4
+ import { component, useLayoutEffect } from '@pionjs/pion';
5
+ import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
6
+ import { style } from './cosmoz-bottom-bar-next.style.js';
7
+ import { toggleSize } from '@neovici/cosmoz-collapse/toggle';
8
+ import { sheet } from '@neovici/cosmoz-utils';
9
+ import '@neovici/cosmoz-dropdown';
10
+
11
+ const BOTTOM_BAR_TOOLBAR_SLOT = 'bottom-bar-toolbar';
12
+ const BOTTOM_BAR_MENU_SLOT = 'bottom-bar-menu';
13
+
14
+ const _moveElement = (element, toToolbar) => {
15
+ const slot = toToolbar ? BOTTOM_BAR_TOOLBAR_SLOT : BOTTOM_BAR_MENU_SLOT;
16
+ const tabindex = '0';
17
+
18
+ element.setAttribute('slot', slot);
19
+ element.setAttribute('tabindex', tabindex);
20
+ };
21
+
22
+ const _isActionNode = (node) => {
23
+ return (
24
+ node.nodeType === Node.ELEMENT_NODE &&
25
+ node.getAttribute('slot') !== 'info' &&
26
+ node.tagName !== 'TEMPLATE' &&
27
+ node.tagName !== 'STYLE' &&
28
+ node.tagName !== 'DOM-REPEAT' &&
29
+ node.tagName !== 'DOM-IF' &&
30
+ node.getAttribute('slot') !== 'extra'
31
+ );
32
+ };
33
+
34
+ const getFlattenedNodes = (element) => {
35
+ const childNodes = [...element.childNodes];
36
+
37
+ for (let i = 0; i < element.childNodes.length; i++) {
38
+ const node = element.childNodes[i];
39
+ if (node.tagName === 'SLOT') {
40
+ // remove current slot element
41
+ childNodes.splice(i, 1);
42
+
43
+ // append slot elements to the current index
44
+ const slotElements = node.assignedElements({ flatten: true });
45
+ for (let j = 0; j < slotElements.length; j++) {
46
+ const slotElement = slotElements[j];
47
+
48
+ childNodes.splice(i + j, 0, slotElement);
49
+ }
50
+ }
51
+ }
52
+
53
+ return childNodes;
54
+ };
55
+
56
+ const _getElements = (host) => {
57
+ const elements = getFlattenedNodes(host)
58
+ .filter(_isActionNode)
59
+ .filter((element) => !element.hidden)
60
+ .sort((a, b) => (a.dataset.index ?? 0) - (b.dataset.index ?? 0));
61
+
62
+ if (elements.length === 0) {
63
+ return elements;
64
+ }
65
+
66
+ const topPriorityAction = elements.reduce(
67
+ (top, element) => {
68
+ return parseInt(top.dataset.priority ?? 0, 10) >=
69
+ parseInt(element.dataset.priority ?? 0, 10)
70
+ ? top
71
+ : element;
72
+ },
73
+ { dataset: { priority: '-1000' } },
74
+ [],
75
+ );
76
+
77
+ return [
78
+ topPriorityAction,
79
+ ...elements.filter((e) => e !== topPriorityAction),
80
+ ];
81
+ };
82
+
83
+ /**
84
+ * Layout the actions available as buttons or menu items
85
+ *
86
+ * If the window is resizing down, just make sure that all buttons fits, and if not,
87
+ * move one to menu and call itself async (to allow re-rendering) and see if we fit.
88
+ * Repeat until the button fits or no buttons are left.
89
+ *
90
+ * If the window is sizing up, try to place a menu item out as a button, call itself
91
+ * async (to allow re-rendering) and see if we fit - if we don't, remove the button again.
92
+ *
93
+ * We also need to keep track of `_scalingUp` between calls since the resize might fire
94
+ * a lot of events, and we don't want to be starting multiple "calculation processes"
95
+ * since this will result in an infinite loop.
96
+ *
97
+ * The actual layouting of actions will be performed by adding or removing the 'button'
98
+ * attribute from the action, which will cause it to match different content insertion
99
+ * points.
100
+ *
101
+ * @param {*} host The current element
102
+ * @param {*} maxToolbarItems Maximum items for the toolbar
103
+ * @returns {void}
104
+ */
105
+ const _layoutActions = (host, maxToolbarItems) => {
106
+ // eslint-disable-line max-statements
107
+ const elements = _getElements(host);
108
+ const hasActions = elements.length > 0;
109
+
110
+ if (!hasActions) {
111
+ // No need to render if we don't have any actions
112
+ return host.toggleAttribute('has-menu-items', false);
113
+ }
114
+
115
+ const toolbarElements = elements.slice(0, maxToolbarItems);
116
+ const menuElements = elements.slice(toolbarElements.length);
117
+
118
+ toolbarElements.forEach((el) => _moveElement(el, true));
119
+ menuElements.forEach((el) => _moveElement(el));
120
+ host.toggleAttribute('has-menu-items', menuElements.length > 0);
121
+ };
122
+
123
+ /**
124
+ * `<cosmoz-bottom-bar>` is a horizontal responsive bottom toolbar containing items that
125
+ * can be used for actions.
126
+ *
127
+ * The items placed inside the `cosmoz-bottom-bar` are distributed into the toolbar in a horizontal container.
128
+ * If the items do not fit the available width, those that do not fit are placed in a dropdown
129
+ * menu triggered by a button in the toolbar.
130
+ * The class specified by the property `toolbarClass` (default `cosmoz-bottom-bar-toolbar`)
131
+ * is applied to items distributed to the toolbar.
132
+ * The class specified in the property `menuClass` (default `cosmoz-bottom-bar-menu`)
133
+ * is applied to items distributed to the menu.
134
+ *
135
+ * ### Usage
136
+ *
137
+ * See demo for example usage
138
+ *
139
+ * @element cosmoz-bottom-bar
140
+ * @demo demo/bottom-bar-next.html Basic Demo
141
+ */
142
+ // eslint-disable-next-line max-statements
143
+ const CosmozBottomBar = ({ active = false, maxToolbarItems = 1 }) => {
144
+ const host = useHost();
145
+
146
+ const toggle = toggleSize('height');
147
+
148
+ useLayoutEffect(() => {
149
+ toggle(host, active);
150
+ }, [active]);
151
+
152
+ const slotChangeHandler = () => {
153
+ _layoutActions(host, maxToolbarItems);
154
+ };
155
+
156
+ return html`<div id="bar" part="bar">
157
+ <div id="info"><slot name="info"></slot></div>
158
+ <slot
159
+ id="bottomBarToolbar"
160
+ name="bottom-bar-toolbar"
161
+ @slotchange=${slotChangeHandler}
162
+ ></slot>
163
+ <cosmoz-dropdown-menu id="dropdown">
164
+ <svg
165
+ slot="button"
166
+ width="4"
167
+ height="16"
168
+ viewBox="0 0 4 16"
169
+ fill="none"
170
+ xmlns="http://www.w3.org/2000/svg"
171
+ >
172
+ <path
173
+ fill-rule="evenodd"
174
+ clip-rule="evenodd"
175
+ d="M1.50996e-07 2C1.02714e-07 3.10457 0.89543 4 2 4C3.10457 4 4 3.10457 4 2C4 0.89543 3.10457 -3.91405e-08 2 -8.74228e-08C0.895431 -1.35705e-07 1.99278e-07 0.89543 1.50996e-07 2Z"
176
+ fill="white"
177
+ />
178
+ <path
179
+ fill-rule="evenodd"
180
+ clip-rule="evenodd"
181
+ d="M1.50996e-07 8C1.02714e-07 9.10457 0.89543 10 2 10C3.10457 10 4 9.10457 4 8C4 6.89543 3.10457 6 2 6C0.895431 6 1.99278e-07 6.89543 1.50996e-07 8Z"
182
+ fill="white"
183
+ />
184
+ <path
185
+ fill-rule="evenodd"
186
+ clip-rule="evenodd"
187
+ d="M1.50996e-07 14C1.02714e-07 15.1046 0.89543 16 2 16C3.10457 16 4 15.1046 4 14C4 12.8954 3.10457 12 2 12C0.895431 12 1.99278e-07 12.8954 1.50996e-07 14Z"
188
+ fill="white"
189
+ />
190
+ </svg>
191
+ <slot id="bottomBarMenu" name="bottom-bar-menu"></slot>
192
+ </cosmoz-dropdown-menu>
193
+ <slot name="extra" id="extraSlot"></slot>
194
+ </div>
195
+ <div hidden style="display:none">
196
+ <slot id="content" @slotchange=${slotChangeHandler}></slot>
197
+ </div>`;
198
+ };
199
+
200
+ export default CosmozBottomBar;
201
+
202
+ customElements.define(
203
+ 'cosmoz-bottom-bar-next',
204
+ component(CosmozBottomBar, {
205
+ observedAttributes: ['active'],
206
+ styleSheets: [sheet(style)],
207
+ }),
208
+ );
@@ -0,0 +1,97 @@
1
+ /* eslint-disable max-len */
2
+ import { css } from '@neovici/cosmoz-utils';
3
+
4
+ export const style = css`
5
+ :host {
6
+ display: block;
7
+ overflow: hidden;
8
+ bottom: 0;
9
+ left: 0;
10
+ width: 100%;
11
+ max-width: 100%; /* Firefox fix */
12
+ background-color: inherit;
13
+ transition: max-height 0.3s ease;
14
+ flex: none;
15
+ background-color: var(
16
+ --cosmoz-bottom-bar-bg-color,
17
+ rgba(230, 230, 230, 0.8)
18
+ );
19
+ box-shadow: var(--cosmoz-bottom-bar-shadow, none);
20
+
21
+ --cosmoz-dropdown-anchor-spacing: 12px 6px;
22
+ --paper-button: {
23
+ background-color: inherit;
24
+ text-transform: none;
25
+ border: 0;
26
+ border-radius: 0;
27
+ font-size: inherit;
28
+ color: inherit;
29
+ font-weight: inherit;
30
+ margin: 0;
31
+ padding: 0;
32
+ };
33
+ }
34
+ :host([force-open]) {
35
+ transition: none;
36
+ }
37
+ [hidden],
38
+ ::slotted([hidden]) {
39
+ display: none !important;
40
+ }
41
+ #bar {
42
+ height: 64px;
43
+ padding: 0 3%;
44
+ display: flex;
45
+ align-items: center;
46
+ }
47
+ #info {
48
+ min-width: 5px;
49
+ padding-right: 3%;
50
+ margin-right: auto;
51
+ white-space: nowrap;
52
+ }
53
+ #bottomBarToolbar::slotted(:not(slot)) {
54
+ margin: 0 0.29em;
55
+ min-width: 40px;
56
+ min-height: 40px;
57
+ text-overflow: ellipsis;
58
+ white-space: nowrap;
59
+ background: var(
60
+ --cosmoz-bottom-bar-button-bg-color,
61
+ var(--cosmoz-button-bg-color, #101010)
62
+ );
63
+ color: var(
64
+ --cosmoz-bottom-bar-button-color,
65
+ var(--cosmoz-button-color, #fff)
66
+ );
67
+ border-radius: 6px;
68
+ padding: 0 18px;
69
+ font-size: 14px;
70
+ font-weight: 500;
71
+ line-height: 40px;
72
+ }
73
+
74
+ #bottomBarToolbar::slotted(:not(slot)[disabled]) {
75
+ opacity: var(--cosmoz-button-disabled-opacity, 0.15);
76
+ pointer-events: none;
77
+ }
78
+ #bottomBarToolbar::slotted(:not(slot):hover) {
79
+ background: var(
80
+ --cosmoz-bottom-bar-button-hover-bg-color,
81
+ var(--cosmoz-button-hover-bg-color, #3a3f44)
82
+ );
83
+ }
84
+ #dropdown::part(content) {
85
+ max-width: 300px;
86
+ }
87
+
88
+ :host([hide-actions]) #bottomBarToolbar,
89
+ :host([hide-actions]) #bottomBarMenu,
90
+ :host([hide-actions]) #dropdown {
91
+ display: none;
92
+ }
93
+
94
+ :host(:not([has-menu-items])) cosmoz-dropdown-menu {
95
+ display: none;
96
+ }
97
+ `;