@neovici/cosmoz-tabs 8.0.0 → 8.2.0

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-tabs",
3
- "version": "8.0.0",
3
+ "version": "8.2.0",
4
4
  "description": "A multi views container element that allow navigation between the views using tabs or an accordion.",
5
5
  "keywords": [
6
6
  "web-components"
@@ -68,6 +68,7 @@
68
68
  "./next/*": "./src/next/*"
69
69
  },
70
70
  "dependencies": {
71
+ "@neovici/cosmoz-collapse": "^1.3.0",
71
72
  "@neovici/cosmoz-router": "^11.0.0",
72
73
  "@neovici/cosmoz-utils": "^6.0.0",
73
74
  "@pionjs/pion": "^2.0.0",
@@ -77,8 +78,8 @@
77
78
  "lit-html": "^2.0.0 || ^3.0.0"
78
79
  },
79
80
  "devDependencies": {
80
- "@commitlint/cli": "^18.0.0",
81
- "@commitlint/config-conventional": "^18.0.0",
81
+ "@commitlint/cli": "^19.0.0",
82
+ "@commitlint/config-conventional": "^19.0.0",
82
83
  "@neovici/cfg": "^1.11.0",
83
84
  "@open-wc/testing": "^4.0.0",
84
85
  "@polymer/iron-list": "^3.1.0",
@@ -87,7 +88,7 @@
87
88
  "@storybook/storybook-deployer": "^2.8.0",
88
89
  "@web/dev-server-storybook": "^2.0.0",
89
90
  "husky": "^8.0.0",
90
- "semantic-release": "^22.0.0",
91
+ "semantic-release": "^23.0.0",
91
92
  "sinon": "^17.0.0",
92
93
  "typescript": "^5.0.0"
93
94
  }
@@ -1,5 +1,18 @@
1
1
  // @license Copyright (C) 2015 Neovici AB - Apache 2 License
2
- import { html, component } from '@pionjs/pion';
2
+ import { html, component, useState, useEffect } from '@pionjs/pion';
3
+ import '@neovici/cosmoz-collapse';
4
+ import { when } from 'lit-html/directives/when.js';
5
+ import { css } from './utils';
6
+
7
+ const collapseIcon = html`<svg
8
+ width="16"
9
+ height="16"
10
+ viewBox="0 0 16 16"
11
+ fill="none"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ >
14
+ <path d="M5 1L10 8L5 15" stroke="#101010" stroke-width="1.5" />
15
+ </svg>`;
3
16
 
4
17
  /**
5
18
 
@@ -19,60 +32,97 @@ Custom property | Description | Default
19
32
  `--cosmoz-tab-card-content-line-height` | Card content line height | `initial`
20
33
  `--cosmoz-tab-card-content-padding` | Card content padding | `initial`
21
34
  */
22
- const CosmozTabCard = ({ heading }) =>
23
- html` <style>
24
- :host {
25
- display: block;
26
- position: relative;
27
- box-sizing: border-box;
28
- background-color: #fff;
29
- border-radius: 3px;
30
- margin: 15px;
31
- align-self: flex-start;
32
- padding: var(--cosmoz-tab-card-padding, 0);
33
- width: var(--cosmoz-tab-card-width, 300px);
34
- box-shadow: var(
35
- --cosmoz-shadow-2dp,
36
- var(--shadow-elevation-2dp_-_box-shadow, 0 2px 4px 0 #e5e5e5)
37
- );
38
- }
39
-
40
- #content {
41
- line-height: var(--cosmoz-tab-card-content-line-height, initial);
42
- padding: var(--cosmoz-tab-card-content-padding, initial);
43
- }
44
-
45
- #header {
46
- display: flex;
47
- align-items: center;
48
- background-color: #fff;
49
- cursor: default;
50
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
51
- }
52
-
53
- .heading {
54
- font-family: inherit;
55
- font-size: 17px;
56
- font-weight: 400;
57
- flex: 1;
58
- margin: 0.67em 0 0;
59
- }
60
- </style>
61
-
62
- <div id="header" part="header">
63
- <h1 class="heading" part="heading">
35
+
36
+ const CosmozTabCard = (host) => {
37
+ const { heading, collapsable, collapsed: isCollapsed } = host,
38
+ [collapsed, setCollapsed] = useState(Boolean(isCollapsed)),
39
+ toggleCollapsed = () => {
40
+ if (!collapsable) return;
41
+ return setCollapsed((c) => !c);
42
+ };
43
+
44
+ useEffect(() => {
45
+ host.toggleAttribute('collapsed', collapsed);
46
+ }, [collapsed]);
47
+
48
+ return html`<div id="header" part="header">
49
+ ${when(
50
+ collapsable,
51
+ () => html`
52
+ <div @click=${toggleCollapsed} part="collapse-icon">
53
+ <slot name="collapse-icon">${collapseIcon}</slot>
54
+ </div>
55
+ `,
56
+ )}
57
+ <h1 class="heading" @click=${toggleCollapsed} part="heading">
64
58
  ${heading}<slot name="after-title"></slot>
65
59
  </h1>
66
60
  <slot name="card-actions"></slot>
67
61
  </div>
68
62
 
69
63
  <div id="content" part="content">
70
- <slot></slot>
64
+ <cosmoz-collapse ?opened=${!collapsed}><slot></slot></cosmoz-collapse>
71
65
  </div>`;
66
+ };
67
+
68
+ const style = css`
69
+ :host {
70
+ display: block;
71
+ position: relative;
72
+ box-sizing: border-box;
73
+ background-color: #fff;
74
+ border-radius: 3px;
75
+ margin: 15px;
76
+ align-self: flex-start;
77
+ padding: var(--cosmoz-tab-card-padding, 0);
78
+ width: var(--cosmoz-tab-card-width, 300px);
79
+ box-shadow: var(
80
+ --cosmoz-shadow-2dp,
81
+ var(--shadow-elevation-2dp_-_box-shadow, 0 2px 4px 0 #e5e5e5)
82
+ );
83
+ }
84
+
85
+ #content {
86
+ line-height: var(--cosmoz-tab-card-content-line-height, initial);
87
+ padding: var(--cosmoz-tab-card-content-padding, initial);
88
+ }
89
+
90
+ #header {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 8px;
94
+ background-color: #fff;
95
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
96
+ }
97
+
98
+ .heading {
99
+ font-family: inherit;
100
+ font-size: 17px;
101
+ font-weight: 400;
102
+ flex: 1;
103
+ }
104
+
105
+ [part='collapse-icon'] {
106
+ order: var(--cosmoz-tab-card-collapse-icon-order);
107
+ transition: transform 250ms linear;
108
+ transform: rotate(90deg);
109
+ }
110
+
111
+ :host([collapsed]) [part='collapse-icon'] {
112
+ transform: rotate(0deg);
113
+ }
114
+
115
+ :host([collapsable]) [part='collapse-icon'],
116
+ :host([collapsable]) .heading {
117
+ cursor: pointer;
118
+ user-select: none;
119
+ }
120
+ `;
72
121
 
73
122
  customElements.define(
74
123
  'cosmoz-tab-card',
75
124
  component(CosmozTabCard, {
76
- observedAttributes: ['heading'],
125
+ observedAttributes: ['heading', 'collapsable', 'collapsed'],
126
+ styleSheets: [style],
77
127
  }),
78
128
  );
@@ -3,6 +3,7 @@ import { html, useMemo, useCallback, useRef } from '@pionjs/pion';
3
3
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
4
  /* eslint-disable-next-line import/no-unresolved */
5
5
  import { useHashParam } from '@neovici/cosmoz-router/use-hash-param';
6
+ import { invoke } from '@neovici/cosmoz-utils/function';
6
7
 
7
8
  const isValid = (tab) => !tab.hidden && !tab.disabled,
8
9
  valid = (tabs) =>
@@ -42,20 +43,21 @@ export const useTabs = (tabs, { hashParam, onActivate }) => {
42
43
  onActivate?.(name);
43
44
  activate(name);
44
45
  },
45
- [activate, onActivate]
46
+ [activate, onActivate],
46
47
  ),
47
48
  };
48
49
  };
49
50
 
50
51
  export const renderTabs = ({ tabs, active, onActivate }) =>
51
- tabs.map(
52
- (tab) => html`<cosmoz-tab-next
52
+ tabs.map((tab) => {
53
+ const title = invoke(tab.title);
54
+ return html`<cosmoz-tab-next
53
55
  name=${tab.name}
54
56
  ?active=${active.name === tab.name}
55
57
  ?hidden=${tab.hidden}
56
58
  ?disabled=${tab.disabled}
57
- title=${ifDefined(typeof tab.title === 'string' ? tab.title : undefined)}
59
+ title=${ifDefined(typeof title === 'string' ? title : undefined)}
58
60
  @click=${onActivate}
59
- >${tab.content ?? tab.title}</cosmoz-tab-next
60
- >`
61
- );
61
+ >${tab.content ?? title}</cosmoz-tab-next
62
+ >`;
63
+ });
package/src/utils.js CHANGED
@@ -1,5 +1,6 @@
1
- const isValid = tab => !tab.hidden && !tab.disabled,
1
+ import { tagged } from '@neovici/cosmoz-utils';
2
2
 
3
+ const isValid = (tab) => !tab.hidden && !tab.disabled,
3
4
  /**
4
5
  * Gets the element icon name.
5
6
  *
@@ -7,10 +8,9 @@ const isValid = tab => !tab.hidden && !tab.disabled,
7
8
  * @param {boolean} isSelected Is the tab selected
8
9
  * @returns {string} Name of the element icon.
9
10
  */
10
- getIcon = (tab, isSelected) => isSelected ? tab.selectedIcon ?? tab.icon : tab.icon,
11
-
12
- getName = tab => tab.getAttribute('name'),
13
-
11
+ getIcon = (tab, isSelected) =>
12
+ isSelected ? tab.selectedIcon ?? tab.icon : tab.icon,
13
+ getName = (tab) => tab.getAttribute('name'),
14
14
  /**
15
15
  * Gets the element icon style property and value if icon color is
16
16
  * set, otherwise return nothing.
@@ -18,19 +18,16 @@ const isValid = tab => !tab.hidden && !tab.disabled,
18
18
  * @param {HTMLElement} tab The tab to compute icon stype for
19
19
  * @returns {string/void} Style color property and value for the icon.
20
20
  */
21
- getIconStyle = tab => {
21
+ getIconStyle = (tab) => {
22
22
  const iconColor = tab.iconColor ?? '#15b0d3';
23
- return ['color: ' + iconColor, tab.iconStyle]
24
- .join(';');
23
+ return ['color: ' + iconColor, tab.iconStyle].join(';');
25
24
  },
26
-
27
- valid = tabs => tabs.find(isValid),
28
-
25
+ valid = (tabs) => tabs.find(isValid),
29
26
  choose = (tabs, selected) => {
30
27
  if (selected == null) {
31
28
  return valid(tabs);
32
29
  }
33
- const selectedTab = tabs.find(tab => getName(tab) === selected);
30
+ const selectedTab = tabs.find((tab) => getName(tab) === selected);
34
31
  if (selectedTab == null) {
35
32
  return valid(tabs);
36
33
  }
@@ -44,21 +41,21 @@ const isValid = tab => !tab.hidden && !tab.disabled,
44
41
  }
45
42
  return fallback;
46
43
  },
47
- collect = slot => slot.assignedElements().flatMap(el => {
48
- if (el.matches('cosmoz-tab')) {
49
- return [el];
50
- }
51
- if (el.matches('slot')) {
52
- return collect(el);
53
- }
54
- return [];
55
- });
44
+ collect = (slot) =>
45
+ slot.assignedElements().flatMap((el) => {
46
+ if (el.matches('cosmoz-tab')) {
47
+ return [el];
48
+ }
49
+ if (el.matches('slot')) {
50
+ return collect(el);
51
+ }
52
+ return [];
53
+ }),
54
+ sheet = (...styles) => {
55
+ const cs = new CSSStyleSheet();
56
+ cs.replaceSync(styles.join(''));
57
+ return cs;
58
+ },
59
+ css = (strings, ...values) => sheet(tagged(strings, ...values));
56
60
 
57
- export {
58
- choose,
59
- collect,
60
- isValid,
61
- getIcon,
62
- getIconStyle,
63
- getName
64
- };
61
+ export { choose, collect, isValid, getIcon, getIconStyle, getName, sheet, css };