@krumio/trailhand-ui 1.4.1 → 1.5.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/README.md +119 -52
- package/dist/components/action-menu/action-menu.d.ts +79 -0
- package/dist/components/action-menu/action-menu.d.ts.map +1 -0
- package/dist/components/action-menu/action-menu.js +333 -0
- package/dist/components/action-menu/action-menu.js.map +1 -0
- package/dist/components/action-menu/action-menu.stories.d.ts +261 -0
- package/dist/components/action-menu/action-menu.stories.d.ts.map +1 -0
- package/dist/components/action-menu/action-menu.stories.js +363 -0
- package/dist/components/action-menu/action-menu.stories.js.map +1 -0
- package/dist/components/action-menu/index.d.ts +2 -0
- package/dist/components/action-menu/index.d.ts.map +1 -0
- package/dist/components/action-menu/index.js +2 -0
- package/dist/components/action-menu/index.js.map +1 -0
- package/dist/components/data-table/data-table.d.ts +191 -0
- package/dist/components/data-table/data-table.d.ts.map +1 -0
- package/dist/components/data-table/data-table.js +857 -0
- package/dist/components/data-table/data-table.js.map +1 -0
- package/dist/components/data-table/data-table.stories.d.ts +507 -0
- package/dist/components/data-table/data-table.stories.d.ts.map +1 -0
- package/dist/components/data-table/data-table.stories.js +601 -0
- package/dist/components/data-table/data-table.stories.js.map +1 -0
- package/dist/components/data-table/index.d.ts +2 -0
- package/dist/components/data-table/index.d.ts.map +1 -0
- package/dist/components/data-table/index.js +2 -0
- package/dist/components/data-table/index.js.map +1 -0
- package/dist/components/th-card/index.d.ts +3 -0
- package/dist/components/th-card/index.d.ts.map +1 -0
- package/dist/components/th-card/index.js +2 -0
- package/dist/components/th-card/index.js.map +1 -0
- package/dist/components/th-card/th-card.d.ts +78 -0
- package/dist/components/th-card/th-card.d.ts.map +1 -0
- package/dist/components/th-card/th-card.js +449 -0
- package/dist/components/th-card/th-card.js.map +1 -0
- package/dist/components/th-card/th-card.stories.d.ts +232 -0
- package/dist/components/th-card/th-card.stories.d.ts.map +1 -0
- package/dist/components/th-card/th-card.stories.js +385 -0
- package/dist/components/th-card/th-card.stories.js.map +1 -0
- package/dist/components/th-tag/index.d.ts +3 -0
- package/dist/components/th-tag/index.d.ts.map +1 -0
- package/dist/components/th-tag/index.js +2 -0
- package/dist/components/th-tag/index.js.map +1 -0
- package/dist/components/th-tag/th-tag.d.ts +65 -0
- package/dist/components/th-tag/th-tag.d.ts.map +1 -0
- package/dist/components/th-tag/th-tag.js +307 -0
- package/dist/components/th-tag/th-tag.js.map +1 -0
- package/dist/components/th-tag/th-tag.stories.d.ts +277 -0
- package/dist/components/th-tag/th-tag.stories.d.ts.map +1 -0
- package/dist/components/th-tag/th-tag.stories.js +415 -0
- package/dist/components/th-tag/th-tag.stories.js.map +1 -0
- package/dist/components/toggle-switch/index.d.ts +2 -0
- package/dist/components/toggle-switch/index.d.ts.map +1 -0
- package/dist/components/toggle-switch/index.js +2 -0
- package/dist/components/toggle-switch/index.js.map +1 -0
- package/dist/components/toggle-switch/toggle-switch.d.ts +38 -0
- package/dist/components/toggle-switch/toggle-switch.d.ts.map +1 -0
- package/dist/components/toggle-switch/toggle-switch.js +175 -0
- package/dist/components/toggle-switch/toggle-switch.js.map +1 -0
- package/dist/components/toggle-switch/toggle-switch.stories.d.ts +239 -0
- package/dist/components/toggle-switch/toggle-switch.stories.d.ts.map +1 -0
- package/dist/components/toggle-switch/toggle-switch.stories.js +408 -0
- package/dist/components/toggle-switch/toggle-switch.stories.js.map +1 -0
- package/dist/design-system/color-palette.stories.d.ts +24 -0
- package/dist/design-system/color-palette.stories.d.ts.map +1 -0
- package/dist/design-system/color-palette.stories.js +361 -0
- package/dist/design-system/color-palette.stories.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +11 -8
package/README.md
CHANGED
|
@@ -1,21 +1,74 @@
|
|
|
1
1
|
# Trailhand UI
|
|
2
2
|
|
|
3
|
-
A component library built with Lit Element web components and Storybook.
|
|
3
|
+
A component library built with Lit Element web components, TypeScript, and Storybook.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @krumio/trailhand-ui
|
|
9
|
+
```
|
|
8
10
|
|
|
9
|
-
##
|
|
11
|
+
## Usage
|
|
10
12
|
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
+
```javascript
|
|
14
|
+
// Import components
|
|
15
|
+
import '@krumio/trailhand-ui/toggle-switch';
|
|
16
|
+
import '@krumio/trailhand-ui/data-table';
|
|
17
|
+
import '@krumio/trailhand-ui/action-menu';
|
|
18
|
+
|
|
19
|
+
// Import global color variables (optional)
|
|
20
|
+
import '@krumio/trailhand-ui/styles/colors.css';
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<!-- Use in HTML -->
|
|
25
|
+
<toggle-switch onLabel="On" offLabel="Off"></toggle-switch>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Global Color Variables
|
|
29
|
+
|
|
30
|
+
Trailhand UI includes a design system with CSS custom properties. Import `colors.css` to use consistent colors across your app:
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
/* Available variables */
|
|
34
|
+
--color-primary: #3d98d3;
|
|
35
|
+
--color-white: #FFFFFF;
|
|
36
|
+
--color-black: #000000;
|
|
37
|
+
|
|
38
|
+
/* Greyscale */
|
|
39
|
+
--color-grey-100 through --color-grey-800
|
|
40
|
+
|
|
41
|
+
/* Semantic aliases */
|
|
42
|
+
--color-text-primary: #212121;
|
|
43
|
+
--color-text-secondary: #636363;
|
|
44
|
+
--color-text-muted: #8D8D8D;
|
|
45
|
+
--color-background: #FFFFFF;
|
|
46
|
+
--color-border: #D7D7D7;
|
|
47
|
+
--color-error: #9F3A3A;
|
|
48
|
+
--color-success: #30AC66;
|
|
49
|
+
--color-warning: #D3C255;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Theming
|
|
53
|
+
|
|
54
|
+
Override any variable to customize the look:
|
|
55
|
+
|
|
56
|
+
```css
|
|
57
|
+
:root {
|
|
58
|
+
--color-primary: #your-brand-color;
|
|
59
|
+
}
|
|
13
60
|
```
|
|
14
61
|
|
|
15
|
-
|
|
62
|
+
## Development
|
|
63
|
+
|
|
64
|
+
### Recommended IDE Setup
|
|
65
|
+
|
|
66
|
+
VSCode with ES6, Lit, and TypeScript plugin support.
|
|
67
|
+
|
|
68
|
+
### Project Setup
|
|
16
69
|
|
|
17
70
|
```bash
|
|
18
|
-
npm
|
|
71
|
+
npm install
|
|
19
72
|
```
|
|
20
73
|
|
|
21
74
|
### Storybook Development
|
|
@@ -40,65 +93,79 @@ npm run build-storybook
|
|
|
40
93
|
|
|
41
94
|
```
|
|
42
95
|
trailhand-ui/
|
|
43
|
-
├──
|
|
44
|
-
├──
|
|
45
|
-
├──
|
|
46
|
-
│ ├──
|
|
47
|
-
│ └──
|
|
48
|
-
├──
|
|
96
|
+
├── src/
|
|
97
|
+
│ ├── components/ # Web components (TypeScript)
|
|
98
|
+
│ │ ├── toggle-switch/
|
|
99
|
+
│ │ ├── data-table/
|
|
100
|
+
│ │ └── action-menu/
|
|
101
|
+
│ ├── design-system/ # Design system stories
|
|
102
|
+
│ └── styles/
|
|
103
|
+
│ └── colors.css # Global color variables
|
|
104
|
+
├── stories/ # Additional Storybook stories
|
|
105
|
+
├── .storybook/ # Storybook configuration
|
|
106
|
+
├── dist/ # Compiled output
|
|
49
107
|
└── package.json
|
|
50
108
|
```
|
|
51
109
|
|
|
52
|
-
##
|
|
53
|
-
|
|
54
|
-
This library uses **Lit Element** for building fast, lightweight web components. Web components are framework-agnostic and work with any JavaScript framework or vanilla JS.
|
|
55
|
-
|
|
56
|
-
### Benefits
|
|
57
|
-
- Framework agnostic
|
|
58
|
-
- Encapsulated styles and functionality
|
|
59
|
-
- Reusable across projects
|
|
60
|
-
- Based on web standards
|
|
110
|
+
## Components
|
|
61
111
|
|
|
62
|
-
|
|
112
|
+
### ToggleSwitch
|
|
63
113
|
|
|
64
|
-
|
|
114
|
+
A reusable toggle for boolean values with sync and persistence features.
|
|
65
115
|
|
|
66
|
-
|
|
116
|
+
```html
|
|
117
|
+
<toggle-switch
|
|
118
|
+
onLabel="On"
|
|
119
|
+
offLabel="Off"
|
|
120
|
+
name="my-toggle"
|
|
121
|
+
storage-key="my-setting"
|
|
122
|
+
></toggle-switch>
|
|
123
|
+
```
|
|
67
124
|
|
|
68
|
-
###
|
|
125
|
+
### DataTable
|
|
69
126
|
|
|
70
|
-
|
|
127
|
+
A sortable, paginated data table with search and custom actions.
|
|
71
128
|
|
|
72
|
-
```
|
|
73
|
-
|
|
129
|
+
```html
|
|
130
|
+
<data-table
|
|
131
|
+
.columns=${columns}
|
|
132
|
+
.data=${data}
|
|
133
|
+
searchable
|
|
134
|
+
paginated
|
|
135
|
+
></data-table>
|
|
74
136
|
```
|
|
75
137
|
|
|
76
|
-
|
|
77
|
-
- Framework: `@storybook/web-components-vite`
|
|
78
|
-
- Addons: `addon-essentials`, `addon-a11y`
|
|
79
|
-
- ES Modules: `"type": "module"` in package.json
|
|
80
|
-
- Version: 8.6.14 (for Node.js v20.18.0 compatibility)
|
|
81
|
-
|
|
82
|
-
### Writing Stories
|
|
138
|
+
### ActionMenu
|
|
83
139
|
|
|
84
|
-
|
|
140
|
+
A dropdown menu for row-level actions in tables.
|
|
85
141
|
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
args: {
|
|
94
|
-
// component props
|
|
95
|
-
},
|
|
96
|
-
};
|
|
142
|
+
```html
|
|
143
|
+
<action-menu
|
|
144
|
+
.actions=${[
|
|
145
|
+
{ id: 'edit', label: 'Edit' },
|
|
146
|
+
{ id: 'delete', label: 'Delete', variant: 'danger' }
|
|
147
|
+
]}
|
|
148
|
+
></action-menu>
|
|
97
149
|
```
|
|
98
150
|
|
|
99
151
|
## Tech Stack
|
|
100
152
|
|
|
101
|
-
- **Lit Element** 3.
|
|
102
|
-
- **
|
|
103
|
-
- **
|
|
153
|
+
- **Lit Element** 3.x - Web component library
|
|
154
|
+
- **TypeScript** - Type safety
|
|
155
|
+
- **Vite** - Build tool
|
|
156
|
+
- **Storybook** 8.x - Component documentation
|
|
157
|
+
- **Vitest** - Testing framework
|
|
104
158
|
- **Node.js** v20.18.0+
|
|
159
|
+
|
|
160
|
+
## Web Components
|
|
161
|
+
|
|
162
|
+
This library uses **Lit Element** for building fast, lightweight web components. Web components are framework-agnostic and work with any JavaScript framework or vanilla JS.
|
|
163
|
+
|
|
164
|
+
### Benefits
|
|
165
|
+
- Framework agnostic
|
|
166
|
+
- Encapsulated styles and functionality
|
|
167
|
+
- Reusable across projects
|
|
168
|
+
- Based on web standards
|
|
169
|
+
- TypeScript support with full type definitions
|
|
170
|
+
|
|
171
|
+
Learn more at [lit.dev](https://lit.dev)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { LitElement, TemplateResult } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* Type definition for resource data
|
|
4
|
+
*/
|
|
5
|
+
interface ResourceData {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
availableActions?: ActionMenuItem[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Type definition for action menu items
|
|
11
|
+
*/
|
|
12
|
+
export interface ActionMenuItem {
|
|
13
|
+
label?: string;
|
|
14
|
+
action?: (resource: ResourceData) => void;
|
|
15
|
+
enabled?: boolean | ((resource: ResourceData) => boolean);
|
|
16
|
+
visible?: boolean | ((resource: ResourceData) => boolean);
|
|
17
|
+
danger?: boolean;
|
|
18
|
+
divider?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A dropdown action menu component for displaying contextual actions.
|
|
22
|
+
* Typically used in table rows or cards to provide action options.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ActionMenu extends LitElement {
|
|
25
|
+
actions: ActionMenuItem[];
|
|
26
|
+
resource: ResourceData;
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
private _isOpen;
|
|
29
|
+
private _boundHandleClickOutside;
|
|
30
|
+
static styles: import("lit").CSSResult;
|
|
31
|
+
constructor();
|
|
32
|
+
connectedCallback(): void;
|
|
33
|
+
disconnectedCallback(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Handle clicks outside the menu to close it
|
|
36
|
+
* @param e - The click event
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
private _handleClickOutside;
|
|
40
|
+
/**
|
|
41
|
+
* Toggle the dropdown menu open/closed
|
|
42
|
+
* @param e - The click event
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
private _toggleMenu;
|
|
46
|
+
/**
|
|
47
|
+
* Handle action click
|
|
48
|
+
* @param e - The click event
|
|
49
|
+
* @param action - The action object
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
private _handleActionClick;
|
|
53
|
+
/**
|
|
54
|
+
* Check if an action is enabled
|
|
55
|
+
* @param action - The action object
|
|
56
|
+
* @returns boolean
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
private _isActionEnabled;
|
|
60
|
+
/**
|
|
61
|
+
* Render the three-dots icon
|
|
62
|
+
* @returns TemplateResult
|
|
63
|
+
* @private
|
|
64
|
+
*/
|
|
65
|
+
private _renderIcon;
|
|
66
|
+
/**
|
|
67
|
+
* Get actions to display
|
|
68
|
+
* @returns Array of actions
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private _getActions;
|
|
72
|
+
/**
|
|
73
|
+
* Render the component
|
|
74
|
+
* @returns TemplateResult
|
|
75
|
+
*/
|
|
76
|
+
render(): TemplateResult;
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=action-menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-menu.d.ts","sourceRoot":"","sources":["../../../src/components/action-menu/action-menu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,cAAc,EAAE,MAAM,KAAK,CAAC;AAG5D;;GAEG;AACH,UAAU,YAAY;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC;IAC1D,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,UAAW,SAAQ,UAAU;IAExC,OAAO,EAAE,cAAc,EAAE,CAAM;IAG/B,QAAQ,EAAE,YAAY,CAAM;IAG5B,QAAQ,UAAS;IAGjB,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,wBAAwB,CAAqB;IAErD,OAAgB,MAAM,0BAkHpB;;IAOO,iBAAiB,IAAI,IAAI;IAKzB,oBAAoB,IAAI,IAAI;IAKrC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAO3B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAOnB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAsB1B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAUnB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAenB;;;OAGG;IACM,MAAM,IAAI,cAAc;CAqFlC"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, html, css } from 'lit';
|
|
8
|
+
import { property, state } from 'lit/decorators.js';
|
|
9
|
+
/**
|
|
10
|
+
* A dropdown action menu component for displaying contextual actions.
|
|
11
|
+
* Typically used in table rows or cards to provide action options.
|
|
12
|
+
*/
|
|
13
|
+
export class ActionMenu extends LitElement {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.actions = [];
|
|
17
|
+
this.resource = {};
|
|
18
|
+
this.disabled = false;
|
|
19
|
+
this._isOpen = false;
|
|
20
|
+
this._boundHandleClickOutside = this._handleClickOutside.bind(this);
|
|
21
|
+
}
|
|
22
|
+
connectedCallback() {
|
|
23
|
+
super.connectedCallback();
|
|
24
|
+
document.addEventListener('click', this._boundHandleClickOutside);
|
|
25
|
+
}
|
|
26
|
+
disconnectedCallback() {
|
|
27
|
+
super.disconnectedCallback();
|
|
28
|
+
document.removeEventListener('click', this._boundHandleClickOutside);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Handle clicks outside the menu to close it
|
|
32
|
+
* @param e - The click event
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
_handleClickOutside(e) {
|
|
36
|
+
const target = e.target;
|
|
37
|
+
if (this._isOpen && !this.contains(target)) {
|
|
38
|
+
this._isOpen = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Toggle the dropdown menu open/closed
|
|
43
|
+
* @param e - The click event
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
46
|
+
_toggleMenu(e) {
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
if (!this.disabled) {
|
|
49
|
+
this._isOpen = !this._isOpen;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Handle action click
|
|
54
|
+
* @param e - The click event
|
|
55
|
+
* @param action - The action object
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
_handleActionClick(e, action) {
|
|
59
|
+
e.stopPropagation();
|
|
60
|
+
if (this._isActionEnabled(action)) {
|
|
61
|
+
this._isOpen = false;
|
|
62
|
+
// Dispatch custom event
|
|
63
|
+
this.dispatchEvent(new CustomEvent('action-click', {
|
|
64
|
+
bubbles: true,
|
|
65
|
+
composed: true,
|
|
66
|
+
detail: { action, resource: this.resource },
|
|
67
|
+
}));
|
|
68
|
+
// Call action handler if provided
|
|
69
|
+
if (action.action && typeof action.action === 'function') {
|
|
70
|
+
action.action(this.resource);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if an action is enabled
|
|
76
|
+
* @param action - The action object
|
|
77
|
+
* @returns boolean
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
_isActionEnabled(action) {
|
|
81
|
+
if (!action.enabled)
|
|
82
|
+
return true;
|
|
83
|
+
if (typeof action.enabled === 'function') {
|
|
84
|
+
return action.enabled(this.resource);
|
|
85
|
+
}
|
|
86
|
+
return action.enabled;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Render the three-dots icon
|
|
90
|
+
* @returns TemplateResult
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
_renderIcon() {
|
|
94
|
+
return html `
|
|
95
|
+
<svg class="action-menu__icon" viewBox="0 0 16 16" fill="currentColor">
|
|
96
|
+
<circle cx="2" cy="8" r="1.5" />
|
|
97
|
+
<circle cx="8" cy="8" r="1.5" />
|
|
98
|
+
<circle cx="14" cy="8" r="1.5" />
|
|
99
|
+
</svg>
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get actions to display
|
|
104
|
+
* @returns Array of actions
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
_getActions() {
|
|
108
|
+
// If actions are provided explicitly, use them
|
|
109
|
+
if (this.actions && this.actions.length > 0) {
|
|
110
|
+
return this.actions;
|
|
111
|
+
}
|
|
112
|
+
// Otherwise, try to get from resource.availableActions
|
|
113
|
+
if (this.resource &&
|
|
114
|
+
typeof this.resource.availableActions !== 'undefined') {
|
|
115
|
+
return this.resource.availableActions || [];
|
|
116
|
+
}
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Render the component
|
|
121
|
+
* @returns TemplateResult
|
|
122
|
+
*/
|
|
123
|
+
render() {
|
|
124
|
+
const allActions = this._getActions();
|
|
125
|
+
// Filter by visibility and enabled status
|
|
126
|
+
let visibleActions = allActions.filter((action) => {
|
|
127
|
+
// Skip dividers in visibility check
|
|
128
|
+
if (action.divider)
|
|
129
|
+
return true;
|
|
130
|
+
// Check visible property
|
|
131
|
+
if (action.visible !== undefined) {
|
|
132
|
+
if (typeof action.visible === 'function') {
|
|
133
|
+
return action.visible(this.resource);
|
|
134
|
+
}
|
|
135
|
+
return action.visible;
|
|
136
|
+
}
|
|
137
|
+
// If no visible property, check enabled (hide if explicitly false)
|
|
138
|
+
if (action.enabled !== undefined && action.enabled === false) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
});
|
|
143
|
+
// Remove consecutive dividers and trailing/leading dividers
|
|
144
|
+
visibleActions = visibleActions.filter((action, index, arr) => {
|
|
145
|
+
if (!action.divider)
|
|
146
|
+
return true;
|
|
147
|
+
// Remove if first or last
|
|
148
|
+
if (index === 0 || index === arr.length - 1)
|
|
149
|
+
return false;
|
|
150
|
+
// Remove if next to another divider
|
|
151
|
+
if (arr[index - 1]?.divider || arr[index + 1]?.divider)
|
|
152
|
+
return false;
|
|
153
|
+
return true;
|
|
154
|
+
});
|
|
155
|
+
return html `
|
|
156
|
+
<button
|
|
157
|
+
class="action-menu__button"
|
|
158
|
+
?disabled=${this.disabled}
|
|
159
|
+
@click=${this._toggleMenu}
|
|
160
|
+
aria-haspopup="true"
|
|
161
|
+
aria-expanded=${this._isOpen}
|
|
162
|
+
>
|
|
163
|
+
${this._renderIcon()}
|
|
164
|
+
</button>
|
|
165
|
+
|
|
166
|
+
<div
|
|
167
|
+
class="action-menu__dropdown ${this._isOpen
|
|
168
|
+
? 'action-menu__dropdown--open'
|
|
169
|
+
: ''}"
|
|
170
|
+
>
|
|
171
|
+
${visibleActions.length === 0
|
|
172
|
+
? html ` <div class="action-menu__empty">No actions available</div> `
|
|
173
|
+
: html `
|
|
174
|
+
<ul class="action-menu__list" role="menu">
|
|
175
|
+
${visibleActions.map((action) => html `
|
|
176
|
+
${action.divider
|
|
177
|
+
? html `
|
|
178
|
+
<li
|
|
179
|
+
class="action-menu__divider"
|
|
180
|
+
role="separator"
|
|
181
|
+
></li>
|
|
182
|
+
`
|
|
183
|
+
: html `
|
|
184
|
+
<li class="action-menu__item" role="none">
|
|
185
|
+
<button
|
|
186
|
+
class="action-menu__action ${action.danger
|
|
187
|
+
? 'action-menu__action--danger'
|
|
188
|
+
: ''}"
|
|
189
|
+
?disabled=${!this._isActionEnabled(action)}
|
|
190
|
+
@click=${(e) => this._handleActionClick(e, action)}
|
|
191
|
+
role="menuitem"
|
|
192
|
+
>
|
|
193
|
+
${action.label}
|
|
194
|
+
</button>
|
|
195
|
+
</li>
|
|
196
|
+
`}
|
|
197
|
+
`)}
|
|
198
|
+
</ul>
|
|
199
|
+
`}
|
|
200
|
+
</div>
|
|
201
|
+
`;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
ActionMenu.styles = css `
|
|
205
|
+
:host {
|
|
206
|
+
display: inline-block;
|
|
207
|
+
position: relative;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.action-menu__button {
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
justify-content: center;
|
|
214
|
+
width: 32px;
|
|
215
|
+
height: 32px;
|
|
216
|
+
padding: 0;
|
|
217
|
+
border: 1px solid var(--border, var(--color-border, #D7D7D7));
|
|
218
|
+
border-radius: 4px;
|
|
219
|
+
background-color: var(--body-bg, var(--color-white, #FFFFFF));
|
|
220
|
+
color: var(--body-text, var(--color-text-primary, #212121));
|
|
221
|
+
cursor: pointer;
|
|
222
|
+
transition: all 0.2s;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.action-menu__button:hover:not(:disabled) {
|
|
226
|
+
background-color: var(--sortable-table-row-hover-bg, var(--color-grey-100, #FAFAFA));
|
|
227
|
+
border-color: var(--link, var(--color-primary, #3d98d3));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.action-menu__button:disabled {
|
|
231
|
+
opacity: 0.4;
|
|
232
|
+
cursor: not-allowed;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.action-menu__icon {
|
|
236
|
+
width: 16px;
|
|
237
|
+
height: 16px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.action-menu__dropdown {
|
|
241
|
+
position: absolute;
|
|
242
|
+
right: 0;
|
|
243
|
+
top: 100%;
|
|
244
|
+
margin-top: 4px;
|
|
245
|
+
min-width: 180px;
|
|
246
|
+
background-color: var(--body-bg, var(--color-white, #FFFFFF));
|
|
247
|
+
border: 1px solid var(--border, var(--color-border, #D7D7D7));
|
|
248
|
+
border-radius: 4px;
|
|
249
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
250
|
+
z-index: 1000;
|
|
251
|
+
opacity: 0;
|
|
252
|
+
visibility: hidden;
|
|
253
|
+
transform: translateY(-10px);
|
|
254
|
+
transition: all 0.2s ease-in-out;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.action-menu__dropdown--open {
|
|
258
|
+
opacity: 1;
|
|
259
|
+
visibility: visible;
|
|
260
|
+
transform: translateY(0);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.action-menu__list {
|
|
264
|
+
list-style: none;
|
|
265
|
+
margin: 0;
|
|
266
|
+
padding: 0.5rem 0;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.action-menu__item {
|
|
270
|
+
margin: 0;
|
|
271
|
+
padding: 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.action-menu__action {
|
|
275
|
+
display: flex;
|
|
276
|
+
align-items: center;
|
|
277
|
+
gap: 0.5rem;
|
|
278
|
+
width: 100%;
|
|
279
|
+
padding: 0.5rem 1rem;
|
|
280
|
+
border: none;
|
|
281
|
+
background: none;
|
|
282
|
+
color: var(--body-text, var(--color-text-primary, #212121));
|
|
283
|
+
font-size: 14px;
|
|
284
|
+
text-align: left;
|
|
285
|
+
cursor: pointer;
|
|
286
|
+
transition: background-color 0.15s;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.action-menu__action:hover:not(:disabled) {
|
|
290
|
+
background-color: var(--sortable-table-row-hover-bg, var(--color-grey-100, #FAFAFA));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.action-menu__action:disabled {
|
|
294
|
+
opacity: 0.4;
|
|
295
|
+
cursor: not-allowed;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.action-menu__action--danger {
|
|
299
|
+
color: var(--error, var(--color-error, #9F3A3A));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.action-menu__action--danger:hover:not(:disabled) {
|
|
303
|
+
background-color: rgba(159, 58, 58, 0.1);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.action-menu__divider {
|
|
307
|
+
height: 1px;
|
|
308
|
+
margin: 0.5rem 0;
|
|
309
|
+
background-color: var(--border, var(--color-border, #D7D7D7));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.action-menu__empty {
|
|
313
|
+
padding: 1rem;
|
|
314
|
+
text-align: center;
|
|
315
|
+
color: var(--muted, var(--color-text-muted, #8D8D8D));
|
|
316
|
+
font-size: 13px;
|
|
317
|
+
}
|
|
318
|
+
`;
|
|
319
|
+
__decorate([
|
|
320
|
+
property({ type: Array })
|
|
321
|
+
], ActionMenu.prototype, "actions", void 0);
|
|
322
|
+
__decorate([
|
|
323
|
+
property({ type: Object })
|
|
324
|
+
], ActionMenu.prototype, "resource", void 0);
|
|
325
|
+
__decorate([
|
|
326
|
+
property({ type: Boolean })
|
|
327
|
+
], ActionMenu.prototype, "disabled", void 0);
|
|
328
|
+
__decorate([
|
|
329
|
+
state()
|
|
330
|
+
], ActionMenu.prototype, "_isOpen", void 0);
|
|
331
|
+
// Register the element
|
|
332
|
+
customElements.define('action-menu', ActionMenu);
|
|
333
|
+
//# sourceMappingURL=action-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-menu.js","sourceRoot":"","sources":["../../../src/components/action-menu/action-menu.ts"],"names":[],"mappings":"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"}
|