@vollowx/seele 0.12.2 → 0.12.4
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
CHANGED
|
@@ -1,38 +1,29 @@
|
|
|
1
1
|
# Standard Extensible Elements
|
|
2
2
|
|
|
3
|
-
**SEELE** is a modern, lightweight
|
|
3
|
+
**SEELE** is a modern, lightweight and accessible
|
|
4
|
+
[Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components)
|
|
5
|
+
library. It provides a set of highly customizable UI components that follow the
|
|
6
|
+
[Material Design 3](https://m3.material.io/) guidelines out of the box, while
|
|
7
|
+
being designed for easy extension and restyling.
|
|
4
8
|
|
|
5
9
|
Visit the [website of SEELE](https://seele.v9.nz/) for documentation and demos.
|
|
6
10
|
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- **Material Design 3**: Ready-to-use components following the latest Material guidelines.
|
|
10
|
-
- **Web Components**: Framework-agnostic. Works with vanilla HTML or any framework.
|
|
11
|
-
- **Extensible**: Built to be extended. Create your own design system on top of SEELE's logic.
|
|
12
|
-
- **Lightweight**: Built on [Lit](https://lit.dev/) and [floating-ui](https://floating-ui.com/) only, ensuring fast performance and small bundle sizes.
|
|
13
|
-
- **Accessible**: Designed with accessibility in mind (using `ElementInternals` and standard ARIA patterns).
|
|
14
|
-
|
|
15
11
|
## Installation
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
SEELE is published on [npm](https://www.npmjs.com/package/@vollowx/seele),
|
|
14
|
+
install with your preferred package manager:
|
|
18
15
|
|
|
19
16
|
```bash
|
|
20
|
-
# npm
|
|
21
17
|
npm install @vollowx/seele
|
|
22
18
|
|
|
23
|
-
# pnpm
|
|
24
|
-
pnpm add @vollowx/seele
|
|
25
|
-
|
|
26
|
-
# yarn
|
|
27
19
|
yarn add @vollowx/seele
|
|
28
20
|
|
|
29
|
-
# bun
|
|
30
21
|
bun add @vollowx/seele
|
|
31
22
|
```
|
|
32
23
|
|
|
33
24
|
## Usage
|
|
34
25
|
|
|
35
|
-
### Importing
|
|
26
|
+
### Importing
|
|
36
27
|
|
|
37
28
|
You can import the entire library or individual components to keep your bundle size small.
|
|
38
29
|
|
|
@@ -40,14 +31,15 @@ You can import the entire library or individual components to keep your bundle s
|
|
|
40
31
|
// Import all components
|
|
41
32
|
import '@vollowx/seele';
|
|
42
33
|
|
|
43
|
-
//
|
|
34
|
+
// Or import specific components (recommended)
|
|
35
|
+
// They all follow such path :@/catagory/group/component.js
|
|
44
36
|
import '@vollowx/seele/m3/button/common-button.js';
|
|
45
37
|
import '@vollowx/seele/m3/checkbox/checkbox.js';
|
|
46
38
|
```
|
|
47
39
|
|
|
48
|
-
### Using
|
|
40
|
+
### Using
|
|
49
41
|
|
|
50
|
-
Once imported,
|
|
42
|
+
Once imported, the components can be used just like standard HTML elements.
|
|
51
43
|
|
|
52
44
|
```html
|
|
53
45
|
<md-button variant="filled">Filled Button</md-button>
|
|
@@ -61,9 +53,15 @@ Once imported, use the components just like standard HTML tags.
|
|
|
61
53
|
|
|
62
54
|
### Theming
|
|
63
55
|
|
|
64
|
-
SEELE components use CSS variables for styling.
|
|
56
|
+
SEELE components use CSS variables for styling.
|
|
57
|
+
|
|
58
|
+
Currently, Material Design 3 token variables are not yet included in the source
|
|
59
|
+
code.
|
|
65
60
|
|
|
66
|
-
To style the components correctly, you need to define the necessary CSS
|
|
61
|
+
To style the components correctly, you need to define the necessary CSS
|
|
62
|
+
variables in your project. You can find reference implementations in
|
|
63
|
+
[vollowx/seele-docs](https://github.com/vollowx/seele-docs/) or the `dev` folder
|
|
64
|
+
of this repository.
|
|
67
65
|
|
|
68
66
|
## Browser Supporty
|
|
69
67
|
|
|
@@ -75,5 +73,5 @@ SEELE relies on modern web standards like `ElementInternals`.
|
|
|
75
73
|
## Resources
|
|
76
74
|
|
|
77
75
|
- [Roadmap](./ROADMAP.md)
|
|
78
|
-
- [Contributing
|
|
76
|
+
- [Contributing](./CONTRIBUTING.md)
|
|
79
77
|
- [License](./LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vollowx/seele",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.4",
|
|
4
4
|
"description": "Standard Extensible Elements. A web components library that can be styled and extended freely, pre-providing components in Material Design 3.",
|
|
5
5
|
"author": "vollowx",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"module": "./src/all.js",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./src/all.js",
|
|
12
|
-
"./
|
|
13
|
-
"./
|
|
12
|
+
"./base/*": "./src/base/*",
|
|
13
|
+
"./m3/*": "./src/m3/*"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"src/**/*.js",
|
package/src/base/list.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
|
|
2
|
-
import { LitElement, html } from 'lit';
|
|
3
|
-
import { property,
|
|
2
|
+
import { LitElement, html, isServer } from 'lit';
|
|
3
|
+
import { property, queryAssignedElements } from 'lit/decorators.js';
|
|
4
4
|
import { setFocusVisible } from '../core/focus-visible.js';
|
|
5
|
-
import { InternalsAttached } from './mixins/internals-attached.js';
|
|
6
|
-
import { FocusDelegated } from './mixins/focus-delegated.js';
|
|
5
|
+
import { InternalsAttached, internals } from './mixins/internals-attached.js';
|
|
7
6
|
import { ListController } from './controllers/list-controller.js';
|
|
8
|
-
const Base =
|
|
7
|
+
const Base = InternalsAttached(LitElement);
|
|
9
8
|
/**
|
|
10
|
-
* @csspart list
|
|
11
9
|
* @csspart items
|
|
12
10
|
*
|
|
13
11
|
* @fires {Event} open - Fires when the menu is opened.
|
|
@@ -18,20 +16,44 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
|
|
|
18
16
|
get $items() {
|
|
19
17
|
return this.listController.items || [];
|
|
20
18
|
}
|
|
19
|
+
constructor(){
|
|
20
|
+
super(), this._possibleItemTags = [], this._scrollPadding = 0, this.noFocusControl = false, this.listController = new ListController(this, {
|
|
21
|
+
isItem: (item)=>this._possibleItemTags.includes(item.tagName.toLowerCase()) && !item.hasAttribute('disabled') && !item.hidden,
|
|
22
|
+
getPossibleItems: ()=>this.slotItems,
|
|
23
|
+
blurItem: (item)=>{
|
|
24
|
+
item.focused = false;
|
|
25
|
+
},
|
|
26
|
+
focusItem: (item)=>{
|
|
27
|
+
item.focused = true;
|
|
28
|
+
if (!this.noFocusControl) {
|
|
29
|
+
this[internals].ariaActiveDescendantElement = item;
|
|
30
|
+
}
|
|
31
|
+
scrollItemIntoView(this, item, this._scrollPadding);
|
|
32
|
+
this.dispatchEvent(new CustomEvent('item-focus', {
|
|
33
|
+
detail: {
|
|
34
|
+
item: item
|
|
35
|
+
},
|
|
36
|
+
bubbles: true,
|
|
37
|
+
composed: true
|
|
38
|
+
}));
|
|
39
|
+
},
|
|
40
|
+
wrapNavigation: ()=>false
|
|
41
|
+
});
|
|
42
|
+
if (!isServer) {
|
|
43
|
+
this[internals].role = 'listbox';
|
|
44
|
+
if (!this.hasAttribute('tabindex')) {
|
|
45
|
+
this.setAttribute('tabindex', '0');
|
|
46
|
+
}
|
|
47
|
+
this.addEventListener('keydown', (e)=>this.#handleKeyDown(e));
|
|
48
|
+
this.addEventListener('focusin', ()=>this.#handleFocusIn());
|
|
49
|
+
this.addEventListener('focusout', ()=>this.#handleFocusOut());
|
|
50
|
+
this.addEventListener('pointerdown', (e)=>this.#handlePointerDown(e));
|
|
51
|
+
this.addEventListener('click', (e)=>this.#handleClick(e));
|
|
52
|
+
this.addEventListener('mouseover', (e)=>this.#handleMouseOver(e));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
21
55
|
render() {
|
|
22
|
-
return html
|
|
23
|
-
part="list"
|
|
24
|
-
role="listbox"
|
|
25
|
-
tabindex="0"
|
|
26
|
-
@keydown=${this.#handleKeyDown}
|
|
27
|
-
@focusin=${this.#handleFocusIn}
|
|
28
|
-
@focusout=${this.#handleFocusOut}
|
|
29
|
-
@pointerdown=${this.#handlePointerDown}
|
|
30
|
-
@click=${this.#handleClick}
|
|
31
|
-
@mouseover=${this.#handleMouseOver}
|
|
32
|
-
>
|
|
33
|
-
${this.renderItemSlot()}
|
|
34
|
-
</div>`;
|
|
56
|
+
return html` ${this.renderItemSlot()} `;
|
|
35
57
|
}
|
|
36
58
|
renderItemSlot() {
|
|
37
59
|
return html`<slot part="items"></slot>`;
|
|
@@ -92,13 +114,13 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
|
|
|
92
114
|
}
|
|
93
115
|
#handlePointerDown(event) {
|
|
94
116
|
event.preventDefault(); // This makes sure that the container is focused
|
|
95
|
-
this
|
|
117
|
+
this.focus();
|
|
96
118
|
const item = this.#getEventItem(event);
|
|
97
119
|
if (!item || !this.listController.items.includes(item)) return;
|
|
98
120
|
this.listController._focusItem(item);
|
|
99
121
|
}
|
|
100
122
|
#handleClick(event) {
|
|
101
|
-
this
|
|
123
|
+
this.focus();
|
|
102
124
|
const item = this.#getEventItem(event);
|
|
103
125
|
if (!item || !this.listController.items.includes(item)) return;
|
|
104
126
|
this.dispatchEvent(new CustomEvent('select', {
|
|
@@ -126,30 +148,6 @@ const Base = FocusDelegated(InternalsAttached(LitElement));
|
|
|
126
148
|
focusItem(item) {
|
|
127
149
|
this.listController._focusItem(item);
|
|
128
150
|
}
|
|
129
|
-
constructor(...args){
|
|
130
|
-
super(...args), this._possibleItemTags = [], this._scrollPadding = 0, this.noFocusControl = false, this.listController = new ListController(this, {
|
|
131
|
-
isItem: (item)=>this._possibleItemTags.includes(item.tagName.toLowerCase()) && !item.hasAttribute('disabled') && !item.hidden,
|
|
132
|
-
getPossibleItems: ()=>this.slotItems,
|
|
133
|
-
blurItem: (item)=>{
|
|
134
|
-
item.focused = false;
|
|
135
|
-
},
|
|
136
|
-
focusItem: (item)=>{
|
|
137
|
-
item.focused = true;
|
|
138
|
-
if (!this.noFocusControl) {
|
|
139
|
-
this.$list.ariaActiveDescendantElement = item;
|
|
140
|
-
}
|
|
141
|
-
scrollItemIntoView(this.$list, item, this._scrollPadding);
|
|
142
|
-
this.dispatchEvent(new CustomEvent('item-focus', {
|
|
143
|
-
detail: {
|
|
144
|
-
item: item
|
|
145
|
-
},
|
|
146
|
-
bubbles: true,
|
|
147
|
-
composed: true
|
|
148
|
-
}));
|
|
149
|
-
},
|
|
150
|
-
wrapNavigation: ()=>false
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
151
|
}
|
|
154
152
|
_ts_decorate([
|
|
155
153
|
property({
|
|
@@ -157,9 +155,6 @@ _ts_decorate([
|
|
|
157
155
|
attribute: 'no-focus-control'
|
|
158
156
|
})
|
|
159
157
|
], List.prototype, "noFocusControl", void 0);
|
|
160
|
-
_ts_decorate([
|
|
161
|
-
query('[part="list"]')
|
|
162
|
-
], List.prototype, "$list", void 0);
|
|
163
158
|
_ts_decorate([
|
|
164
159
|
queryAssignedElements({
|
|
165
160
|
flatten: true
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const listStyles = css`:host{
|
|
2
|
+
export const listStyles = css`:host{box-sizing:border-box;-webkit-user-select:none;user-select:none;outline:0;flex-direction:column;gap:2px;min-width:112px;height:max-content;padding:4px;display:flex;position:relative;overflow-y:auto}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const menuStyles = css`:host{min-width:112px;display:contents}[part=menu]{background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-shadow-2);box-sizing:border-box;color:var(--md-sys-color-on-surface);height:inherit;max-height:var(--md-menu-max-height,inherit);max-width:inherit;min-width:inherit;opacity:0;-webkit-user-select:none;user-select:none;z-index:1000;border-radius:16px;outline:0;padding:4px;position:absolute;inset:auto;overflow-y:auto;transform:scaleY(.
|
|
2
|
+
export const menuStyles = css`:host{min-width:112px;display:contents}[part=menu]{background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-shadow-2);box-sizing:border-box;color:var(--md-sys-color-on-surface);height:inherit;max-height:var(--md-menu-max-height,inherit);max-width:inherit;min-width:inherit;opacity:0;-webkit-user-select:none;user-select:none;z-index:1000;border-radius:16px;outline:0;padding:4px;position:absolute;inset:auto;overflow-y:auto;transform:scaleY(.35)}:host([color=vibrant]){& [part=menu]{--md-divider-color:var(--md-sys-color-tertiary);--md-item-supporting-text-color:var(--md-sys-color-on-tertiary-container);background-color:var(--md-sys-color-tertiary-container);color:var(--md-sys-color-on-tertiary-container)}& ::slotted([selected]){--md-item-supporting-text-color:var(--md-sys-color-on-tertiary);background-color:var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary)}}:host([alignstrategy=fixed]) [part=menu]{position:fixed}[part=items]{opacity:0;flex-direction:column;gap:2px;display:flex}:host(:state(closed)) [part=menu]{display:none}:host(:state(opening)){& [part=menu]{opacity:1;transition:opacity 67ms, transform var(--md-sys-motion-exp-spatial-default-duration) var(--md-sys-motion-exp-spatial-default);display:block;transform:scaleY(1)}& [part=items]{opacity:1;transition:opacity 67ms linear 67ms}}:host(:state(opened)){& [part=menu]{opacity:1;display:block;transform:scaleY(1)}& [part=items]{opacity:1}}:host(:state(closing)){& [part=menu]{opacity:0;transition:opacity var(--md-sys-motion-exp-effects-fast-duration), transform var(--md-sys-motion-exp-effects-slow-duration) var(--md-sys-motion-exp-effects-slow);transform:scaleY(.35)}& [part=items]{opacity:0;transition:opacity 67ms}}::slotted(md-divider){margin-block:6px}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const textFieldStyles = css`:host{-webkit-user-select:none;user-select:none;min-width:210px;display:inline-block}md-filled-field,md-outlined-field{width:100%}[part=input]{color:inherit;font:inherit;background:0 0;border:none;outline:none;width:100%;height:100%;margin:0;padding:0}`;
|
|
2
|
+
export const textFieldStyles = css`:host{-webkit-user-select:none;user-select:none;min-width:210px;display:inline-block}md-filled-field,md-outlined-field{width:100%}[part=input]{color:inherit;font:inherit;-webkit-tap-highlight-color:transparent;background:0 0;border:none;outline:none;width:100%;height:100%;margin:0;padding:0}`;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
export const tooltipStyles = css`:host{background-color:var(--md-sys-color-inverse-surface);box-sizing:border-box;color:#0000;font:var(--md-sys-typography-body-small);max-width:var(--_max-width,300px);opacity:0;pointer-events:none;z-index:800;border-radius:4px;align-items:center;width:max-content;min-height:24px;padding:4px 8px;display:flex;position:absolute;top:0;left:0;transform:scaleY(.
|
|
2
|
+
export const tooltipStyles = css`:host{background-color:var(--md-sys-color-inverse-surface);box-sizing:border-box;color:#0000;font:var(--md-sys-typography-body-small);max-width:var(--_max-width,300px);opacity:0;pointer-events:none;z-index:800;border-radius:4px;align-items:center;width:max-content;min-height:24px;padding:4px 8px;display:flex;position:absolute;top:0;left:0;transform:scaleY(.35)}:host(:state(closed)){display:none}:host(:state(opening):not([forceinvisible])){color:var(--md-sys-color-inverse-on-surface);opacity:1;pointer-events:auto;transition:color linear 67ms 67ms, opacity var(--md-sys-motion-exp-effects-fast-duration) var(--md-sys-motion-exp-effects-fast), transform var(--md-sys-motion-exp-effects-fast-duration) var(--md-sys-motion-exp-effects-fast);transform:scaleY(1)}:host(:state(opened):not([forceinvisible])){color:var(--md-sys-color-inverse-on-surface);opacity:1;pointer-events:auto;transform:scaleY(1)}:host(:state(closing):not([forceinvisible])){color:#0000;opacity:0;transition:color linear 67ms, opacity var(--md-sys-motion-exp-effects-fast-duration) var(--md-sys-motion-exp-effects-fast), transform var(--md-sys-motion-exp-effects-fast-duration) var(--md-sys-motion-exp-effects-fast);transform:scaleY(.35)}`;
|