@operato/menu 7.1.31 → 7.1.32

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.
@@ -1,162 +0,0 @@
1
- import { css } from 'lit'
2
-
3
- export const MenuPortraitStyles = css`
4
- :host {
5
- display: flex;
6
- overflow-y: auto;
7
- flex-direction: column;
8
- height: 100%;
9
- background-color: var(--md-sys-color-on-primary);
10
- }
11
-
12
- :host > ul {
13
- margin-block-end: 1.5em;
14
- }
15
-
16
- ul {
17
- list-style: none;
18
- margin: var(--spacing-none);
19
- padding: var(--spacing-none);
20
- }
21
-
22
- [group-label] {
23
- padding: var(--spacing-huge) var(--spacing-none) var(--spacing-small) var(--spacing-large);
24
- border-bottom: var(--border-dim-color);
25
- font: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500)) 12px var(--theme-font);
26
- color: var(--md-sys-color-primary);
27
- text-transform: uppercase;
28
- }
29
-
30
- a {
31
- display: flex;
32
- align-items: center;
33
- border-bottom: 1px solid rgba(0, 0, 0, 0.07);
34
- padding: var(--spacing-medium);
35
- padding-left: var(--spacing-large);
36
- text-decoration: none;
37
- font: normal var(--md-sys-typescale-label-large-size, 0.875rem) var(--theme-font);
38
- color: var(--md-sys-color-on-surface-variant);
39
- text-transform: capitalize;
40
-
41
- overflow: hidden;
42
- white-space: nowrap;
43
- text-overflow: ellipsis;
44
- }
45
-
46
- a:hover {
47
- color: var(--md-sys-color-primary);
48
- font-weight: bold;
49
- }
50
-
51
- a * {
52
- vertical-align: middle;
53
- }
54
-
55
- a md-icon {
56
- --md-icon-size: var(--icon-size-tiny);
57
- opacity: 0.7;
58
- margin-right: var(--spacing-small);
59
- color: var(--md-sys-color-primary);
60
- }
61
-
62
- md-icon[filled] {
63
- font-variation-settings: 'FILL' 1;
64
- }
65
-
66
- a [submenu-button] {
67
- --md-icon-size: var(--icon-size-tiny);
68
- max-height: 1em;
69
- margin-left: auto;
70
- }
71
-
72
- a [submenu-button]::before {
73
- content: 'chevron_right';
74
- }
75
-
76
- a > span {
77
- flex: 1;
78
- overflow: hidden;
79
- white-space: nowrap;
80
- text-overflow: ellipsis;
81
- }
82
-
83
- li[active] > a [submenu-button]::before {
84
- content: 'expand_more';
85
- }
86
-
87
- li[active] > a {
88
- color: var(--md-sys-color-on-primary-container);
89
- font-weight: bold;
90
- border-left: 3px solid var(--md-sys-color-primary);
91
- }
92
-
93
- li li a {
94
- padding: var(--spacing-medium);
95
- padding-left: var(--spacing-huge);
96
- font: normal 13px var(--theme-font);
97
- color: var(--md-sys-color-on-surface-variant);
98
- }
99
-
100
- li li[active] a {
101
- background-color: var(--md-sys-color-primary-container);
102
- font: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500))
103
- var(--md-sys-typescale-label-large-size, 0.875rem) var(--theme-font);
104
- color: var(--md-sys-color-primary);
105
- }
106
-
107
- li > ul {
108
- overflow-y: hidden;
109
- max-height: 0;
110
- background-color: var(--md-sys-color-surface);
111
-
112
- transition-property: all;
113
- transition-duration: 0.7s;
114
- }
115
-
116
- li[active] > ul {
117
- max-height: 500px;
118
- }
119
-
120
- li[active] > ul[settled] {
121
- overflow-y: auto;
122
- }
123
-
124
- li li a::before {
125
- margin-right: var(--spacing-small);
126
- }
127
-
128
- a [badge] {
129
- margin-left: auto;
130
- background-color: var(--md-sys-color-primary);
131
- border-radius: var(--md-sys-shape-corner-full);
132
- padding: 0 var(--spacing-small);
133
- color: var(--md-sys-color-on-primary);
134
- font-size: 0.9em;
135
- }
136
-
137
- @media only screen and (max-width: 460px) {
138
- :host {
139
- min-width: 100vw;
140
- }
141
-
142
- a {
143
- padding: var(--spacing-large);
144
- font: normal 15px var(--theme-font);
145
- }
146
-
147
- li li a {
148
- display: block;
149
- padding: var(--spacing-medium);
150
- padding-left: var(--spacing-huge);
151
- overflow: hidden;
152
- text-overflow: ellipsis;
153
- white-space: nowrap;
154
- font: normal var(--md-sys-typescale-label-large-size, 0.875rem) var(--theme-font);
155
- }
156
-
157
- li li[active] a {
158
- font: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500))
159
- var(--md-sys-typescale-label-large-size, 0.875rem) var(--theme-font);
160
- }
161
- }
162
- `
@@ -1,105 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import { html, LitElement } from 'lit'
4
- import { customElement, property, query, state } from 'lit/decorators.js'
5
- import { connect } from 'pwa-helpers'
6
-
7
- import { navigate, store } from '@operato/shell'
8
- import { ScrollbarStyles } from '@operato/styles'
9
-
10
- import { Menu } from './types'
11
- import { MenuLandscapeStyles } from './menu-landscape-styles'
12
-
13
- @customElement('ox-menu-landscape')
14
- export class OxMenuLandscape extends connect(store)(LitElement) {
15
- static styles = [ScrollbarStyles, MenuLandscapeStyles]
16
-
17
- @property({ type: Array }) menus?: Menu[]
18
- @property({ type: Object }) activeTopLevel?: Menu
19
- @property({ type: Object }) activeMenu!: Menu
20
- @property({ type: String }) path?: string
21
-
22
- render() {
23
- const { menus = [], activeTopLevel, activeMenu } = this
24
-
25
- return html`
26
- <div id="wrap" @mousewheel=${this.onWheelEvent.bind(this)}>
27
- <ul>
28
- ${menus.map(menu =>
29
- menu.type == 'group'
30
- ? html``
31
- : html`
32
- <li ?active=${menu === activeTopLevel}>
33
- <a href=${menu.path || '#'}>
34
- ${menu.icon ? html`<md-icon>${menu.icon}</md-icon>` : html``} ${menu.label || menu.name}
35
- </a>
36
-
37
- <ul submenus>
38
- ${menu.menus?.map(
39
- menu => html`
40
- <li ?active=${menu === activeMenu}>
41
- <a href=${menu.path || '#'}> ${menu.label || menu.name} </a>
42
- </li>
43
- `
44
- )}
45
- </ul>
46
-
47
- <div description>
48
- ${menu.icon ? html`<md-icon>${menu.icon}</md-icon>` : html``} ${menu.description || ''}
49
- </div>
50
- </li>
51
- `
52
- )}
53
- </ul>
54
- </div>
55
- `
56
- }
57
-
58
- firstUpdated() {
59
- this.renderRoot.addEventListener('click', (e: Event) => {
60
- //@ts-ignore
61
- if (e.target.submenu) {
62
- /* protect to act move to href. */
63
- e.stopPropagation()
64
- e.preventDefault()
65
-
66
- //@ts-ignore
67
- let menu = e.target.submenu
68
-
69
- this.dispatchEvent(
70
- new CustomEvent('active-toplevel', {
71
- bubbles: true,
72
- detail: this.activeTopLevel === menu ? undefined : menu
73
- })
74
- )
75
-
76
- return
77
- }
78
-
79
- /* to respond even if current acting menu is selected */
80
- let href = (e.target as HTMLAnchorElement).href
81
- href && location.href === href && navigate(href + '#force', true)
82
- })
83
-
84
- /* to hide scrollbar during transition */
85
- this.renderRoot.addEventListener('transitionstart', e => {
86
- ;(e.target as HTMLElement).removeAttribute('settled')
87
- })
88
- this.renderRoot.addEventListener('transitionend', e => {
89
- ;(e.target as HTMLElement).setAttribute('settled', '')
90
- })
91
- }
92
-
93
- onWheelEvent(e: WheelEvent) {
94
- const { target, deltaY, detail } = e
95
-
96
- if (!(target instanceof HTMLElement)) {
97
- return
98
- }
99
-
100
- const delta = deltaY || -detail
101
- target.scrollLeft -= (delta / Math.abs(delta)) * 10
102
-
103
- e.preventDefault()
104
- }
105
- }
@@ -1,131 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import './ox-menu-portrait'
3
- import './ox-menu-landscape'
4
-
5
- import { css, html, LitElement, PropertyValues } from 'lit'
6
- import { customElement, property, query, state } from 'lit/decorators.js'
7
- import { connect } from 'pwa-helpers'
8
-
9
- import { store } from '@operato/shell'
10
- import { ScrollbarStyles } from '@operato/styles'
11
-
12
- import { Menu } from './types'
13
-
14
- function isActiveMenu(menu: Menu, path: string) {
15
- return (
16
- menu.path?.split('?')[0] === path ||
17
- (menu.active && typeof menu.active === 'function' && menu.active.call(menu, { path }))
18
- )
19
- }
20
-
21
- @customElement('ox-menu-part')
22
- export class OxMenuPart extends connect(store)(LitElement) {
23
- static styles = [
24
- ScrollbarStyles,
25
- css`
26
- :host {
27
- display: flex;
28
- overflow-y: auto;
29
- flex-direction: column;
30
- height: 100%;
31
- min-width: 200px;
32
- background-color: var(--md-sys-color-surface);
33
- }
34
-
35
- :host([landscape]) {
36
- overflow-x: auto;
37
- flex-direction: row;
38
- width: 100%;
39
- min-height: 20px;
40
- }
41
-
42
- ox-menu-portrait,
43
- ox-menu-landscape {
44
- flex: 1;
45
- }
46
- `
47
- ]
48
-
49
- @property({ type: String }) page!: string
50
- @property({ type: String }) resourceId?: string
51
- @property({ type: Array }) menus?: Menu[]
52
- @property({ type: String }) orientation?: 'landscape' | 'portrait'
53
-
54
- @state() slotTemplate: any
55
- @state() _activeTopLevel?: Menu
56
- @state() _activeMenu?: Menu
57
- @state() _path?: string
58
-
59
- render() {
60
- return html`
61
- <slot name="head"></slot>
62
- ${this.orientation !== 'landscape'
63
- ? html`<ox-menu-portrait
64
- .menus=${this.menus}
65
- .activeTopLevel=${this._activeTopLevel}
66
- .activeMenu=${this._activeMenu}
67
- .path=${this._path}
68
- ></ox-menu-portrait>`
69
- : html`<ox-menu-landscape
70
- .menus=${this.menus}
71
- .activeTopLevel=${this._activeTopLevel}
72
- .activeMenu=${this._activeMenu}
73
- .path=${this._path}
74
- ></ox-menu-landscape>`}
75
- <slot name="tail"></slot>
76
- `
77
- }
78
-
79
- firstUpdated() {
80
- this.renderRoot.addEventListener('active-toplevel', (e: Event) => {
81
- e.stopPropagation()
82
- e.preventDefault()
83
-
84
- this._activeTopLevel = (e as CustomEvent).detail
85
- })
86
- }
87
-
88
- updated(changes: PropertyValues<this>) {
89
- if (changes.has('menus') || changes.has('page') || changes.has('resourceId')) {
90
- this.findActivePage()
91
- }
92
-
93
- if (changes.has('orientation')) {
94
- if (this.orientation == 'portrait') {
95
- this.removeAttribute('landscape')
96
- } else {
97
- this.setAttribute('landscape', '')
98
- }
99
- }
100
-
101
- if (changes.has('slotTemplate')) {
102
- this.replaceChild(this.slotTemplate, this.renderRoot)
103
- }
104
- }
105
-
106
- stateChanged(state: any): void {
107
- this.page = state.route.page
108
- this.resourceId = state.route.resourceId
109
- this.menus = state.liteMenu.menus || []
110
- this.slotTemplate = state.liteMenu.slotTemplate
111
- }
112
-
113
- private findActivePage() {
114
- var path = this.resourceId ? `${this.page}/${this.resourceId}` : this.page
115
- var menus = this.menus || []
116
- var activeMenu
117
-
118
- this._activeTopLevel = menus.find(menu => {
119
- if (isActiveMenu(menu, path)) {
120
- activeMenu = menu
121
- return true
122
- } else if (menu.menus) {
123
- activeMenu = menu.menus.find(menu => isActiveMenu(menu, path))
124
- return !!activeMenu
125
- }
126
- })
127
-
128
- this._path = path
129
- this._activeMenu = activeMenu || this._activeTopLevel
130
- }
131
- }
@@ -1,91 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import { html, LitElement, nothing, TemplateResult } from 'lit'
4
- import { customElement, property } from 'lit/decorators.js'
5
-
6
- import { navigate } from '@operato/shell'
7
- import { ScrollbarStyles } from '@operato/styles'
8
-
9
- import { Menu } from './types'
10
- import { MenuPortraitStyles } from './menu-portrait-styles'
11
-
12
- @customElement('ox-menu-portrait')
13
- export class OxMenuPortrait extends LitElement {
14
- static styles = [ScrollbarStyles, MenuPortraitStyles]
15
-
16
- @property({ type: Array }) menus?: Menu[]
17
- @property({ type: Object }) activeTopLevel?: Menu
18
- @property({ type: Object }) activeMenu?: Menu
19
- @property({ type: String }) path!: string
20
-
21
- renderMenus(menus: Menu[], activeTopLevel?: Menu, activeMenu?: Menu): TemplateResult | typeof nothing {
22
- if (menus.length == 0) {
23
- return nothing
24
- }
25
-
26
- return html`
27
- <ul>
28
- ${menus.map(menu => {
29
- var { type, name, active, path, label = name, badge, icon, menus = [] } = menu
30
- active = active && typeof active === 'function' ? active.call(menu, { path: this.path }) : false
31
- badge = typeof badge === 'function' ? badge.call(menu) : badge ?? false
32
-
33
- return type == 'group'
34
- ? html`<li group-label>${label}</li>`
35
- : html`
36
- <li ?active=${activeTopLevel ? menu === activeTopLevel : active} .menu=${menu} menu>
37
- <a href=${path || '#'}>
38
- <md-icon filled>${icon || 'fiber_manual_record'}</md-icon>
39
- <span>${label}</span>${badge !== false ? html`<div badge>${badge}</div>` : html``}
40
- ${menus.length > 0 ? html` <md-icon filled submenu-button></md-icon> ` : html``}
41
- </a>
42
- ${menus && this.renderMenus(menus || [], activeMenu)}
43
- </li>
44
- `
45
- })}
46
- </ul>
47
- `
48
- }
49
-
50
- render() {
51
- const { menus, activeTopLevel, activeMenu } = this
52
- return this.renderMenus(menus || [], activeTopLevel, activeMenu)
53
- }
54
-
55
- firstUpdated() {
56
- this.renderRoot.addEventListener('click', (e: Event) => {
57
- const menuElement = (e.target as Element)!.closest('[menu]')
58
-
59
- //@ts-ignore
60
- if (menuElement?.menu) {
61
- //@ts-ignore
62
- let menu = menuElement.menu
63
-
64
- if (!menu.path) {
65
- /* protect to act move to href. */
66
- e.stopPropagation()
67
- e.preventDefault()
68
- }
69
-
70
- this.dispatchEvent(
71
- new CustomEvent('active-toplevel', {
72
- bubbles: true,
73
- detail: this.activeTopLevel === menu ? undefined : menu
74
- })
75
- )
76
- }
77
-
78
- /* to respond even if current acting menu is selected */
79
- let href = (e.target as HTMLAnchorElement)!.href
80
- href && location.href === href && navigate(href + '#force', true)
81
- })
82
-
83
- /* to hide scrollbar during transition */
84
- this.renderRoot.addEventListener('transitionstart', e => {
85
- ;(e.target as Element).removeAttribute('settled')
86
- })
87
- this.renderRoot.addEventListener('transitionend', e => {
88
- ;(e.target as Element).setAttribute('settled', '')
89
- })
90
- }
91
- }
@@ -1,147 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import { css, html, LitElement, PropertyValueMap, TemplateResult } from 'lit'
4
- import { customElement, property, query, state } from 'lit/decorators.js'
5
- import { connect } from 'pwa-helpers'
6
-
7
- import { toggleOverlay } from '@operato/layout'
8
- import { store } from '@operato/shell'
9
-
10
- import { Menu } from './types'
11
-
12
- @customElement('ox-top-menu-bar')
13
- export class OxTopMenuBar extends connect(store)(LitElement) {
14
- static styles = [
15
- css`
16
- :host {
17
- display: flex;
18
- flex-direction: row;
19
- }
20
-
21
- span {
22
- flex: 1;
23
- }
24
-
25
- ul {
26
- display: flex;
27
- align-items: center;
28
- list-style: none;
29
- margin: 0;
30
- padding: 0;
31
- }
32
-
33
- li {
34
- display: inline-flex;
35
- flex-direction: row nowrap;
36
- float: left;
37
- overflow: none;
38
- }
39
-
40
- a {
41
- display: inline-block;
42
- white-space: nowrap;
43
- overflow: hidden;
44
- text-overflow: ellipsis;
45
- padding: var(--padding-default) var(--spacing-large) var(--spacing-small) var(--spacing-large);
46
- text-decoration: none;
47
- color: white;
48
- }
49
- a * {
50
- vertical-align: middle;
51
- }
52
- a md-icon {
53
- opacity: 0.5;
54
- position: relative;
55
- top: -2px;
56
- font-size: 1em;
57
- }
58
-
59
- li[active] a {
60
- font-weight: bold;
61
- }
62
- li[active] a md-icon {
63
- opacity: 1;
64
- }
65
- `
66
- ]
67
-
68
- @property({ type: String }) page?: string
69
- @property({ type: String }) resourceId?: string
70
- @property({ type: Array }) menus?: Menu[]
71
- @property({ type: Object }) slotTemplate!: Node
72
-
73
- @state() private _activeTopLevel?: Menu
74
-
75
- render() {
76
- const { menus = [], _activeTopLevel } = this
77
-
78
- return html`
79
- <slot name="head"></slot>
80
- <ul>
81
- ${menus.map(menu =>
82
- menu.type == 'group'
83
- ? html``
84
- : html`
85
- <li ?active=${menu === _activeTopLevel}>
86
- <a
87
- href="#"
88
- @click=${(e: MouseEvent) => {
89
- e.preventDefault()
90
- toggleOverlay('ox-menu-part', {
91
- backdrop: true
92
- })
93
- }}
94
- >
95
- ${menu.name}
96
- <md-icon>expand_more</md-icon>
97
- </a>
98
- </li>
99
- `
100
- )}
101
- </ul>
102
- <slot name="tail"></slot>
103
- `
104
- }
105
-
106
- stateChanged(state: any): void {
107
- this.page = state.route.page
108
- this.resourceId = state.route.resourceId
109
- this.menus = state.liteMenu.menus || []
110
- this.slotTemplate = state.liteMenu.slotTemplate
111
- }
112
-
113
- // firstUpdated() {
114
- // this.addEventListener('mousewheel', this.onWheelEvent.bind(this), false)
115
- // }
116
-
117
- updated(changes: PropertyValueMap<this>) {
118
- if (changes.has('menus') || changes.has('page') || changes.has('resourceId')) {
119
- this._findActivePage()
120
- }
121
-
122
- if (changes.has('slotTemplate')) {
123
- this.replaceChild(this.slotTemplate, this.renderRoot)
124
- }
125
- }
126
-
127
- // onWheelEvent(e) {
128
- // var delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail))
129
- // this.scrollLeft -= delta * 40
130
- // console.log('delta', this.scrollLeft, delta, e.wheelDelta || -e.detail)
131
-
132
- // e.preventDefault()
133
- // }
134
-
135
- _findActivePage() {
136
- var path = this.resourceId ? `${this.page}/${this.resourceId}` : this.page
137
- var menus = this.menus || []
138
-
139
- this._activeTopLevel = menus.find(menu => {
140
- if (menu.path?.split('?')[0] === path) {
141
- return true
142
- } else if (menu.menus) {
143
- return !!menu.menus.find(menu => menu.path?.split('?')[0] === path)
144
- }
145
- })
146
- }
147
- }
package/src/types.ts DELETED
@@ -1,11 +0,0 @@
1
- export type Menu = {
2
- type?: 'group' | 'board'
3
- name?: string
4
- description?: string
5
- path?: string
6
- icon?: string
7
- label?: string
8
- badge?: boolean | string | (() => boolean)
9
- active?: boolean | ((menu?: Menu) => boolean)
10
- menus?: Menu[]
11
- }