@neovici/cosmoz-tabs 5.3.0 → 5.4.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": "5.3.0",
3
+ "version": "5.4.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"
@@ -15,21 +15,19 @@
15
15
  },
16
16
  "license": "Apache-2.0",
17
17
  "author": "Neovici Development <dev@neovici.se>",
18
- "main": "cosmoz-tabs.js",
18
+ "main": "src/index.js",
19
19
  "directories": {
20
20
  "test": "test"
21
21
  },
22
22
  "files": [
23
- "cosmoz-*.js",
24
- "lib/**/*.js"
23
+ "src/**/*.js"
25
24
  ],
26
25
  "scripts": {
27
26
  "lint": "eslint --cache --ext .js .",
28
27
  "lint-tsc": "tsc",
29
- "start": "npm run storybook",
28
+ "start": "wds",
30
29
  "test": "wtr --coverage",
31
30
  "test:watch": "wtr --watch",
32
- "storybook": "start-storybook --node-resolve --watch --open",
33
31
  "storybook:build": "build-storybook",
34
32
  "storybook:deploy": "storybook-to-ghpages",
35
33
  "prepare": "husky install"
@@ -53,8 +51,16 @@
53
51
  "@commitlint/config-conventional"
54
52
  ]
55
53
  },
54
+ "exports": {
55
+ ".": "./src/index.js",
56
+ "./cosmoz-tabs": "./src/cosmoz-tabs.js",
57
+ "./cosmoz-tab": "./src/cosmoz-tab.js",
58
+ "./cosmoz-tab-card": "./src/cosmoz-tab-card.js",
59
+ "./cosmoz-tab-card.js": "./src/cosmoz-tab-card.js",
60
+ "./next/*": "./src/next/*"
61
+ },
56
62
  "dependencies": {
57
- "@neovici/cosmoz-page-router": "^7.0.0",
63
+ "@neovici/cosmoz-page-router": "^8.0.0",
58
64
  "@neovici/cosmoz-utils": "^3.25.0",
59
65
  "@polymer/iron-icon": "^3.0.0",
60
66
  "@polymer/iron-icons": "^3.0.0",
@@ -63,19 +69,19 @@
63
69
  "lit-html": "^1.4.0"
64
70
  },
65
71
  "devDependencies": {
66
- "@commitlint/cli": "^16.0.0",
67
- "@commitlint/config-conventional": "^16.0.0",
72
+ "@commitlint/cli": "^17.0.0",
73
+ "@commitlint/config-conventional": "^17.0.0",
68
74
  "@neovici/cfg": "^1.11.0",
69
- "@open-wc/demoing-storybook": "^2.4.0",
70
75
  "@open-wc/testing": "^2.5.0",
71
76
  "@polymer/iron-list": "^3.1.0",
72
77
  "@semantic-release/changelog": "^6.0.0",
73
78
  "@semantic-release/git": "^10.0.0",
74
79
  "@storybook/storybook-deployer": "^2.8.0",
80
+ "@web/dev-server-storybook": "^0.5.0",
75
81
  "@web/test-runner": "^0.13.18",
76
- "husky": "^7.0.0",
82
+ "husky": "^8.0.0",
77
83
  "semantic-release": "^19.0.0",
78
- "sinon": "^13.0.0",
84
+ "sinon": "^14.0.0",
79
85
  "typescript": "^4.4.0"
80
86
  }
81
87
  }
File without changes
@@ -4,7 +4,7 @@ import {
4
4
  html,
5
5
  component
6
6
  } from 'haunted';
7
- import { useTab } from './lib/use-tab';
7
+ import { useTab } from './use-tab';
8
8
 
9
9
  /**
10
10
 
@@ -1,7 +1,7 @@
1
1
  // @license Copyright (C) 2015 Neovici AB - Apache 2 License
2
2
  import { html, component } from 'haunted';
3
- import { useTabs } from './lib/use-tabs';
4
- import { style, renderTab } from './lib/render';
3
+ import { useTabs } from './use-tabs';
4
+ import { style, renderTab } from './render';
5
5
  import './cosmoz-tab.js';
6
6
  import '@polymer/iron-icon';
7
7
  import '@polymer/iron-icons';
package/src/index.js ADDED
@@ -0,0 +1 @@
1
+ import './cosmoz-tabs';
@@ -0,0 +1,68 @@
1
+ import { tagged as css } from '@neovici/cosmoz-utils';
2
+
3
+ export default css`
4
+ :host {
5
+ position: relative;
6
+ display: flex;
7
+ box-sizing: border-box;
8
+ align-items: center;
9
+ justify-content: center;
10
+ flex: 1;
11
+ padding: 11px 24px;
12
+ color: inherit;
13
+ text-decoration: none;
14
+ text-align: center;
15
+ letter-spacing: 0.3px;
16
+ text-overflow: ellipsis;
17
+ white-space: nowrap;
18
+ cursor: pointer;
19
+ /* TODO(accessibility): focused tab should be outlined */
20
+ outline: 0;
21
+ }
22
+
23
+ :host([active]) {
24
+ color: var(--cosmoz-tabs-accent-color, #508aef);
25
+ box-shadow: inset 0 -3px 0px 0px var(--cosmoz-tabs-accent-color, #508aef);
26
+ font-weight: 700;
27
+ letter-spacing: 0;
28
+ }
29
+
30
+ :host([disabled]) {
31
+ opacity: 0.4;
32
+ pointer-events: none;
33
+ }
34
+
35
+ #iconSlot::slotted(*) {
36
+ flex-shrink: 0;
37
+ }
38
+
39
+ #contentSlot::slotted(*) {
40
+ flex: auto;
41
+ }
42
+
43
+ .badge {
44
+ font-family: var(--cosmoz-font-base, 'Verdana, Arial, sans-serif');
45
+ font-weight: normal;
46
+ font-size: 11px;
47
+ line-height: 1;
48
+ border-radius: 0.90909em;
49
+ box-sizing: border-box;
50
+
51
+ transform: translateY(-50%);
52
+ vertical-align: top;
53
+ min-width: 1.81818em;
54
+ padding: 0.40909em 0.36363em;
55
+
56
+ max-width: 80px;
57
+ text-overflow: ellipsis;
58
+ overflow: hidden;
59
+
60
+ background-color: var(--accent-color, #ff4081);
61
+ color: #ffffff;
62
+ text-align: center;
63
+ }
64
+
65
+ a {
66
+ display: contents;
67
+ }
68
+ `;
@@ -0,0 +1,53 @@
1
+ import { component, useEffect, useLayoutEffect } from 'haunted';
2
+ import { html, nothing } from 'lit-html';
3
+ import { ifDefined } from 'lit-html/directives/if-defined';
4
+ import computeScroll from 'compute-scroll-into-view';
5
+
6
+ import style from './cosmoz-tab.css';
7
+
8
+ const Tab = (host) => {
9
+ const { active, badge, href } = host;
10
+
11
+ useEffect(() => {
12
+ if (!host.getAttribute('tabindex')) {
13
+ host.setAttribute('tabindex', '-1');
14
+ }
15
+ host.setAttribute('role', 'tab');
16
+ }, []);
17
+
18
+ useLayoutEffect(() => {
19
+ const el = host;
20
+ el.toggleAttribute('aria-selected', !!active);
21
+
22
+ if (!active) {
23
+ return;
24
+ }
25
+ computeScroll(el, {
26
+ block: 'nearest',
27
+ inline: 'center',
28
+ boundary: el.parentElement,
29
+ }).forEach(({ el, top, left }) =>
30
+ el.scroll({ top, left, behavior: 'smooth' })
31
+ );
32
+ }, [active]);
33
+
34
+ return html`
35
+ <style>
36
+ ${style}
37
+ </style>
38
+ <a part="link" href=${ifDefined(href)}>
39
+ <slot id="iconSlot" name="icon"></slot>
40
+ <slot id="contentSlot"></slot>
41
+ ${badge
42
+ ? html`<span class="badge" part="badge">${badge}</span>`
43
+ : nothing}
44
+ </a>
45
+ `;
46
+ };
47
+
48
+ customElements.define(
49
+ 'cosmoz-tab-next',
50
+ component(Tab, {
51
+ observedAttributes: ['active', 'badge', 'href'],
52
+ })
53
+ );
@@ -0,0 +1,22 @@
1
+ import { tagged as css } from '@neovici/cosmoz-utils';
2
+
3
+ export default css`
4
+ :host {
5
+ background-color: var(--cosmoz-tabs-bg-color, #fff);
6
+ color: var(--cosmoz-tabs-text-color, #606c7e);
7
+ font-family: var(--cosmoz-tabs-font-family, inherit);
8
+ font-size: var(--cosmoz-tabs-font-size, 13px);
9
+ line-height: var(--cosmoz-tabs-line-height, 19px);
10
+ box-shadow: var(--cosmoz-tabs-shadow, inset 0 -1px 0 0 #e5e6eb);
11
+ flex: none;
12
+ display: flex;
13
+ align-items: center;
14
+ overflow-x: auto;
15
+ -webkit-overflow-scrolling: auto;
16
+ scrollbar-width: none;
17
+ padding-bottom: 1px;
18
+ }
19
+ :host::-webkit-scrollbar {
20
+ display: none;
21
+ }
22
+ `;
@@ -0,0 +1,17 @@
1
+ import { html, component, useEffect } from 'haunted';
2
+ import style from './cosmoz-tabs.css';
3
+
4
+ const Tabs = (host) => {
5
+ useEffect(() => {
6
+ host.setAttribute('role', 'tablist');
7
+ }, []);
8
+
9
+ return html`
10
+ <style>
11
+ ${style}
12
+ </style>
13
+ <slot></slot>
14
+ `;
15
+ };
16
+
17
+ customElements.define('cosmoz-tabs-next', component(Tabs));
@@ -0,0 +1,4 @@
1
+ import './cosmoz-tabs';
2
+ import './cosmoz-tab';
3
+
4
+ export * from './use-tabs';
@@ -0,0 +1,50 @@
1
+ /* eslint-disable import/group-exports */
2
+ import { html, useMemo, useCallback, useRef } from 'haunted';
3
+ import { useHashParam } from '@neovici/cosmoz-page-router/lib/use-hash-param';
4
+
5
+ const isValid = (tab) => !tab.hidden && !tab.disabled,
6
+ valid = (tabs) => tabs.find(isValid),
7
+ choose = (tabs, name) => {
8
+ const tab = name && tabs.find((tab) => tab.name === name);
9
+ return tab && isValid(tab) ? tab : valid(tabs);
10
+ };
11
+
12
+ export const useTabs = (tabs, { hashParam }) => {
13
+ const [name, activate] = useHashParam(hashParam),
14
+ ref = useRef([]),
15
+ active = useMemo(() => choose(tabs, name), [tabs, name]),
16
+ activated = useMemo(() => {
17
+ const name = active.name;
18
+ return (ref.current = [...ref.current.filter((i) => i !== name), name]);
19
+ }, [active]),
20
+ onActivate = useCallback(
21
+ (e) => {
22
+ if (e.button !== 0 || e.metaKey || e.ctrlKey) {
23
+ return;
24
+ }
25
+ const { name } = e.currentTarget;
26
+ activate(name);
27
+ },
28
+ [activate]
29
+ );
30
+
31
+ return {
32
+ tabs,
33
+ active,
34
+ activated,
35
+ activate,
36
+ onActivate,
37
+ };
38
+ };
39
+
40
+ export const renderTabs = ({ tabs, active, onActivate }) =>
41
+ tabs.map(
42
+ (tab) => html`<cosmoz-tab-next
43
+ name=${tab.name}
44
+ ?active=${active.name === tab.name}
45
+ ?hidden=${tab.hidden}
46
+ ?disabled=${tab.disabled}
47
+ @click=${onActivate}
48
+ >${tab.title}</cosmoz-tab-next
49
+ >`
50
+ );
File without changes
File without changes
@@ -48,7 +48,7 @@ const useTabSelectedEffect = (host, selectedTab) => {
48
48
  selected, hashParam
49
49
  } = host,
50
50
  [tabs, setTabs] = useState([]),
51
- param = useHashParam(hashParam),
51
+ [param] = useHashParam(hashParam),
52
52
  selection = hashParam == null || param == null && selected != null ? selected : param,
53
53
  selectedTab = useMemo(() => choose(tabs, selection), [tabs, selection]);
54
54
 
File without changes