@santi020k/lumen-elements 1.6.0 → 1.7.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 +80 -5
- package/bin/lumen.mjs +2 -0
- package/dist/components/badge.d.ts +21 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +20 -0
- package/dist/components/button.d.ts +38 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +35 -0
- package/dist/components/card.d.ts +25 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +23 -0
- package/dist/components/combobox.d.ts +23 -0
- package/dist/components/combobox.d.ts.map +1 -0
- package/dist/components/combobox.js +138 -0
- package/dist/components/foundations.d.ts +161 -0
- package/dist/components/foundations.d.ts.map +1 -0
- package/dist/components/foundations.js +173 -0
- package/dist/define.d.ts +169 -150
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +1 -1
- package/dist/element-base.d.ts +26 -0
- package/dist/element-base.d.ts.map +1 -0
- package/dist/element-base.js +66 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/package.json +31 -3
- package/styles/critical.css +2054 -0
package/README.md
CHANGED
|
@@ -10,19 +10,32 @@ This package registers standards-based custom elements for the shared Lumen prim
|
|
|
10
10
|
pnpm add @santi020k/lumen-elements
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
The adapter also exposes Lumen's discovery and diagnostics CLI:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm exec lumen show Tabs
|
|
17
|
+
pnpm exec lumen doctor
|
|
18
|
+
```
|
|
19
|
+
|
|
13
20
|
Load the shared stylesheet once from your app entry or global CSS.
|
|
14
21
|
|
|
15
22
|
```css
|
|
16
23
|
@import "@santi020k/lumen-elements/styles.css";
|
|
17
24
|
```
|
|
18
25
|
|
|
26
|
+
Pair granular registrations with `@santi020k/lumen-elements/styles/critical.css` when the product
|
|
27
|
+
uses only the essential forms, feedback, tabs, dialogs, calendar, and data-table surface. Use the
|
|
28
|
+
complete stylesheet for the full element catalog.
|
|
29
|
+
|
|
19
30
|
The stylesheet defaults `--ui-font` to `"Montserrat", "Avenir Next", "Segoe UI", sans-serif`.
|
|
20
31
|
It declares the family stack but does not bundle or load font files. Load Montserrat once through
|
|
21
32
|
your preferred delivery path, or override `--ui-font` in application CSS.
|
|
22
33
|
|
|
23
34
|
## Usage
|
|
24
35
|
|
|
25
|
-
Register the elements once, then use `lumen-*` tags anywhere HTML is
|
|
36
|
+
Register the elements once per custom-element registry, then use `lumen-*` tags anywhere HTML is
|
|
37
|
+
valid. Repeated calls are idempotent, and an explicitly supplied scoped registry is populated
|
|
38
|
+
independently from the document registry.
|
|
26
39
|
|
|
27
40
|
```html
|
|
28
41
|
<script type="module">
|
|
@@ -38,6 +51,60 @@ Register the elements once, then use `lumen-*` tags anywhere HTML is valid.
|
|
|
38
51
|
</lumen-card>
|
|
39
52
|
```
|
|
40
53
|
|
|
54
|
+
To limit registration to the tags a scoped surface owns, pass their catalog names before an
|
|
55
|
+
optional custom registry:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { defineLumenElements } from '@santi020k/lumen-elements/define'
|
|
59
|
+
|
|
60
|
+
defineLumenElements(['Card', 'Input', 'Button'])
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The component-name list is typed, duplicate names are ignored, already-registered tags are
|
|
64
|
+
preserved, and omitting it retains complete-catalog registration. This controls registry scope, but
|
|
65
|
+
the `define` module still contains the complete implementation.
|
|
66
|
+
|
|
67
|
+
For a small surface that uses only Badge, Button, Card, and Combobox, import their implementation-level
|
|
68
|
+
entrypoints instead:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { defineLumenBadge } from '@santi020k/lumen-elements/components/badge'
|
|
72
|
+
import { defineLumenButton } from '@santi020k/lumen-elements/components/button'
|
|
73
|
+
import { defineLumenCard } from '@santi020k/lumen-elements/components/card'
|
|
74
|
+
import { defineLumenCombobox } from '@santi020k/lumen-elements/components/combobox'
|
|
75
|
+
|
|
76
|
+
defineLumenBadge()
|
|
77
|
+
defineLumenButton()
|
|
78
|
+
defineLumenCard()
|
|
79
|
+
defineLumenCombobox()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Each function accepts an optional custom-element registry, is idempotent, and registers the exact
|
|
83
|
+
constructor used by the complete catalog. The Combobox entrypoint includes its filtering, keyboard,
|
|
84
|
+
selection, dismissal, and focus behavior without importing the complete catalog. Other components
|
|
85
|
+
still use `defineLumenElements`; do not replace the full entrypoint when the application needs a
|
|
86
|
+
behavior-backed element that does not yet have a granular module.
|
|
87
|
+
|
|
88
|
+
Foundation-only pages can register fifteen layout, composition, and accessibility elements as one
|
|
89
|
+
small implementation-level bundle:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { defineLumenFoundations } from '@santi020k/lumen-elements/components/foundations'
|
|
93
|
+
|
|
94
|
+
defineLumenFoundations()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This bundle contains the Card compound parts, Container, Direction, Grid, Label, Separator,
|
|
98
|
+
Skeleton, Spinner, Stack, Typography, and VisuallyHidden. It does not import the complete catalog.
|
|
99
|
+
|
|
100
|
+
`lumen-phone-input` can generate its complete country and telephone controls. It exposes `value`,
|
|
101
|
+
`valid`, and `e164`, and emits `ui:phone-change` with the normalized phone model. Country names and
|
|
102
|
+
calling codes remain visible so the flag is never the only identifier.
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<lumen-phone-input country="CO" locale="en-US" name="hospitalPhone"></lumen-phone-input>
|
|
106
|
+
```
|
|
107
|
+
|
|
41
108
|
## Language selection
|
|
42
109
|
|
|
43
110
|
`lumen-language-toggle` cycles through an ordered JSON `locales` list and generates visible
|
|
@@ -88,8 +155,7 @@ internal native control provides the same contract when `ElementInternals` is un
|
|
|
88
155
|
```
|
|
89
156
|
|
|
90
157
|
`lumen-input` forwards the numeric `size` attribute to its internal native input. Use
|
|
91
|
-
`visual-size="sm"` or `visual-size="lg"` for presentation.
|
|
92
|
-
remains available for incremental migrations.
|
|
158
|
+
`visual-size="sm"` or `visual-size="lg"` for presentation.
|
|
93
159
|
|
|
94
160
|
```html
|
|
95
161
|
<lumen-input name="code" size="12" visual-size="sm"></lumen-input>
|
|
@@ -167,8 +233,8 @@ attribute form is useful for static HTML and server output.
|
|
|
167
233
|
></lumen-line-chart>
|
|
168
234
|
```
|
|
169
235
|
|
|
170
|
-
`lumen-sparkline` also accepts comma-separated or JSON `values`.
|
|
171
|
-
|
|
236
|
+
`lumen-sparkline` also accepts comma-separated or JSON `values`. Every data chart includes a
|
|
237
|
+
revealable semantic table unless `show-table="false"` is set. `lumen-pie-chart` uses the first
|
|
172
238
|
serialized series and defaults to `variant="donut"`.
|
|
173
239
|
|
|
174
240
|
## Optimized images
|
|
@@ -222,6 +288,8 @@ their registered custom elements; no Astro runtime or host controller is require
|
|
|
222
288
|
Rich text controls may provide `data-ui-editor-value` for commands such as `formatBlock` and
|
|
223
289
|
`createLink`; editable surfaces emit `ui:editor-change` with both HTML and plain text, support common
|
|
224
290
|
formatting shortcuts, and keep toggle controls synchronized through `aria-pressed`.
|
|
291
|
+
`lumen-tabs` keeps the selected trigger visible in narrow horizontal lists and emits
|
|
292
|
+
`ui:tabs-change`; import `LumenTabsChangeDetail` or `LumenTabsChangeEvent` for its typed detail.
|
|
225
293
|
|
|
226
294
|
`<lumen-kanban-board>` and `<lumen-kanban-column value="…">` provide the same controlled board
|
|
227
295
|
contract. Mark ordinary card items with `data-ui-kanban-item` and put `data-ui-kanban-handle` on a
|
|
@@ -254,6 +322,13 @@ You can also use the shared document events: dispatch `ui:toast` to create, `ui:
|
|
|
254
322
|
update, and `ui:toast-dismiss` to dismiss runtime toasts. Toast actions emit `ui:toast-action`
|
|
255
323
|
unless an action supplies a custom event name.
|
|
256
324
|
|
|
325
|
+
Use `<lumen-error-state>` when a region or page cannot show its primary content. Keep its visible
|
|
326
|
+
heading, explanation, optional safe reference, and recovery actions in light DOM, label the region
|
|
327
|
+
with `aria-labelledby`, and use the documented `data-slot="error-state-*"` hooks. Lumen presents the
|
|
328
|
+
failure; application code owns exception capture, logging, and retry policy. See the repository
|
|
329
|
+
[Web Components error-handling guide](../../docs/error-handling.md#web-components) for the complete
|
|
330
|
+
light-DOM structure, ARIA ownership, retry boundary, and verification guidance.
|
|
331
|
+
|
|
257
332
|
## Motion
|
|
258
333
|
|
|
259
334
|
The elements adapter exposes the same motion vocabulary as Astro and React. Use
|
package/bin/lumen.mjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type LumenCustomElementRegistry } from '../element-base.js';
|
|
2
|
+
export declare const lumenBadgeElementConfig: {
|
|
3
|
+
readonly attributeClasses: {
|
|
4
|
+
readonly variant: {
|
|
5
|
+
readonly default: "ui-badge--default";
|
|
6
|
+
readonly destructive: "ui-badge--destructive";
|
|
7
|
+
readonly outline: "ui-badge--outline";
|
|
8
|
+
readonly secondary: "ui-badge--secondary";
|
|
9
|
+
readonly success: "ui-badge--success";
|
|
10
|
+
readonly warning: "ui-badge--warning";
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
readonly baseClassName: "ui-badge";
|
|
14
|
+
readonly defaults: {
|
|
15
|
+
readonly variant: "default";
|
|
16
|
+
};
|
|
17
|
+
readonly tagName: "lumen-badge";
|
|
18
|
+
};
|
|
19
|
+
export declare const LumenBadgeElement: import("../element-base.js").LumenElementConstructor;
|
|
20
|
+
export declare const defineLumenBadge: (registry?: LumenCustomElementRegistry) => void;
|
|
21
|
+
//# sourceMappingURL=badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/components/badge.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAEhC,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;CAcG,CAAA;AAEvC,eAAO,MAAM,iBAAiB,sDAE7B,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,WAAW,0BAA0B,KACpC,IAEF,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createLumenElementClass, defineLumenElement } from '../element-base.js';
|
|
2
|
+
export const lumenBadgeElementConfig = {
|
|
3
|
+
attributeClasses: {
|
|
4
|
+
variant: {
|
|
5
|
+
default: 'ui-badge--default',
|
|
6
|
+
destructive: 'ui-badge--destructive',
|
|
7
|
+
outline: 'ui-badge--outline',
|
|
8
|
+
secondary: 'ui-badge--secondary',
|
|
9
|
+
success: 'ui-badge--success',
|
|
10
|
+
warning: 'ui-badge--warning'
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
baseClassName: 'ui-badge',
|
|
14
|
+
defaults: { variant: 'default' },
|
|
15
|
+
tagName: 'lumen-badge'
|
|
16
|
+
};
|
|
17
|
+
export const LumenBadgeElement = createLumenElementClass(lumenBadgeElementConfig);
|
|
18
|
+
export const defineLumenBadge = (registry) => {
|
|
19
|
+
defineLumenElement(lumenBadgeElementConfig, LumenBadgeElement, registry);
|
|
20
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type LumenCustomElementRegistry } from '../element-base.js';
|
|
2
|
+
export declare const lumenButtonElementConfig: {
|
|
3
|
+
readonly attributeClasses: {
|
|
4
|
+
readonly variant: {
|
|
5
|
+
readonly default: "ui-button--default";
|
|
6
|
+
readonly destructive: "ui-button--destructive";
|
|
7
|
+
readonly ghost: "ui-button--ghost";
|
|
8
|
+
readonly link: "ui-button--link";
|
|
9
|
+
readonly outline: "ui-button--outline";
|
|
10
|
+
readonly secondary: "ui-button--secondary";
|
|
11
|
+
};
|
|
12
|
+
readonly size: {
|
|
13
|
+
readonly default: "ui-button--default-size";
|
|
14
|
+
readonly icon: "ui-button--icon";
|
|
15
|
+
readonly lg: "ui-button--lg";
|
|
16
|
+
readonly sm: "ui-button--sm";
|
|
17
|
+
};
|
|
18
|
+
readonly disabled: {
|
|
19
|
+
readonly true: "ui-button--disabled";
|
|
20
|
+
};
|
|
21
|
+
readonly loading: {
|
|
22
|
+
readonly true: "ui-button--loading";
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
readonly baseClassName: "ui-button";
|
|
26
|
+
readonly defaults: {
|
|
27
|
+
readonly 'data-slot': "button";
|
|
28
|
+
readonly role: "button";
|
|
29
|
+
readonly size: "default";
|
|
30
|
+
readonly tabindex: "0";
|
|
31
|
+
readonly variant: "default";
|
|
32
|
+
};
|
|
33
|
+
readonly role: "button";
|
|
34
|
+
readonly tagName: "lumen-button";
|
|
35
|
+
};
|
|
36
|
+
export declare const LumenButtonElement: import("../element-base.js").LumenElementConstructor;
|
|
37
|
+
export declare const defineLumenButton: (registry?: LumenCustomElementRegistry) => void;
|
|
38
|
+
//# sourceMappingURL=button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/components/button.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAEhC,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BE,CAAA;AAEvC,eAAO,MAAM,kBAAkB,sDAE9B,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,WAAW,0BAA0B,KACpC,IAEF,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createLumenElementClass, defineLumenElement } from '../element-base.js';
|
|
2
|
+
export const lumenButtonElementConfig = {
|
|
3
|
+
attributeClasses: {
|
|
4
|
+
variant: {
|
|
5
|
+
default: 'ui-button--default',
|
|
6
|
+
destructive: 'ui-button--destructive',
|
|
7
|
+
ghost: 'ui-button--ghost',
|
|
8
|
+
link: 'ui-button--link',
|
|
9
|
+
outline: 'ui-button--outline',
|
|
10
|
+
secondary: 'ui-button--secondary'
|
|
11
|
+
},
|
|
12
|
+
size: {
|
|
13
|
+
default: 'ui-button--default-size',
|
|
14
|
+
icon: 'ui-button--icon',
|
|
15
|
+
lg: 'ui-button--lg',
|
|
16
|
+
sm: 'ui-button--sm'
|
|
17
|
+
},
|
|
18
|
+
disabled: { true: 'ui-button--disabled' },
|
|
19
|
+
loading: { true: 'ui-button--loading' }
|
|
20
|
+
},
|
|
21
|
+
baseClassName: 'ui-button',
|
|
22
|
+
defaults: {
|
|
23
|
+
'data-slot': 'button',
|
|
24
|
+
role: 'button',
|
|
25
|
+
size: 'default',
|
|
26
|
+
tabindex: '0',
|
|
27
|
+
variant: 'default'
|
|
28
|
+
},
|
|
29
|
+
role: 'button',
|
|
30
|
+
tagName: 'lumen-button'
|
|
31
|
+
};
|
|
32
|
+
export const LumenButtonElement = createLumenElementClass(lumenButtonElementConfig);
|
|
33
|
+
export const defineLumenButton = (registry) => {
|
|
34
|
+
defineLumenElement(lumenButtonElementConfig, LumenButtonElement, registry);
|
|
35
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type LumenCustomElementRegistry } from '../element-base.js';
|
|
2
|
+
export declare const lumenCardElementConfig: {
|
|
3
|
+
readonly attributeClasses: {
|
|
4
|
+
readonly glass: {
|
|
5
|
+
readonly strong: "ui-card--glass ui-glass-strong";
|
|
6
|
+
readonly subtle: "ui-card--glass ui-glass-subtle";
|
|
7
|
+
readonly true: "ui-card--glass";
|
|
8
|
+
};
|
|
9
|
+
readonly variant: {
|
|
10
|
+
readonly glass: "ui-card--glass";
|
|
11
|
+
readonly interactive: "ui-card--interactive";
|
|
12
|
+
readonly muted: "ui-card--muted";
|
|
13
|
+
readonly unstyled: "ui-card--unstyled";
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
readonly baseClassName: "ui-card";
|
|
17
|
+
readonly defaults: {
|
|
18
|
+
readonly 'data-slot': "card";
|
|
19
|
+
readonly variant: "default";
|
|
20
|
+
};
|
|
21
|
+
readonly tagName: "lumen-card";
|
|
22
|
+
};
|
|
23
|
+
export declare const LumenCardElement: import("../element-base.js").LumenElementConstructor;
|
|
24
|
+
export declare const defineLumenCard: (registry?: LumenCustomElementRegistry) => void;
|
|
25
|
+
//# sourceMappingURL=card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/components/card.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAEhC,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;CAiBI,CAAA;AAEvC,eAAO,MAAM,gBAAgB,sDAE5B,CAAA;AAED,eAAO,MAAM,eAAe,GAC1B,WAAW,0BAA0B,KACpC,IAEF,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createLumenElementClass, defineLumenElement } from '../element-base.js';
|
|
2
|
+
export const lumenCardElementConfig = {
|
|
3
|
+
attributeClasses: {
|
|
4
|
+
glass: {
|
|
5
|
+
strong: 'ui-card--glass ui-glass-strong',
|
|
6
|
+
subtle: 'ui-card--glass ui-glass-subtle',
|
|
7
|
+
true: 'ui-card--glass'
|
|
8
|
+
},
|
|
9
|
+
variant: {
|
|
10
|
+
glass: 'ui-card--glass',
|
|
11
|
+
interactive: 'ui-card--interactive',
|
|
12
|
+
muted: 'ui-card--muted',
|
|
13
|
+
unstyled: 'ui-card--unstyled'
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
baseClassName: 'ui-card',
|
|
17
|
+
defaults: { 'data-slot': 'card', variant: 'default' },
|
|
18
|
+
tagName: 'lumen-card'
|
|
19
|
+
};
|
|
20
|
+
export const LumenCardElement = createLumenElementClass(lumenCardElementConfig);
|
|
21
|
+
export const defineLumenCard = (registry) => {
|
|
22
|
+
defineLumenElement(lumenCardElementConfig, LumenCardElement, registry);
|
|
23
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type LumenCustomElementRegistry, LumenElement } from '../element-base.js';
|
|
2
|
+
export declare const lumenComboboxElementConfig: {
|
|
3
|
+
readonly baseClassName: "ui-combobox";
|
|
4
|
+
readonly defaults: {
|
|
5
|
+
readonly 'data-ui-combobox': "";
|
|
6
|
+
};
|
|
7
|
+
readonly tagName: "lumen-combobox";
|
|
8
|
+
};
|
|
9
|
+
export declare class LumenComboboxElement extends LumenElement {
|
|
10
|
+
static config: {
|
|
11
|
+
readonly baseClassName: "ui-combobox";
|
|
12
|
+
readonly defaults: {
|
|
13
|
+
readonly 'data-ui-combobox': "";
|
|
14
|
+
};
|
|
15
|
+
readonly tagName: "lumen-combobox";
|
|
16
|
+
};
|
|
17
|
+
private abortController;
|
|
18
|
+
connectedCallback(): void;
|
|
19
|
+
disconnectedCallback(): void;
|
|
20
|
+
private setupCombobox;
|
|
21
|
+
}
|
|
22
|
+
export declare const defineLumenCombobox: (registry?: LumenCustomElementRegistry) => void;
|
|
23
|
+
//# sourceMappingURL=combobox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../src/components/combobox.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAC/B,YAAY,EAEb,MAAM,oBAAoB,CAAA;AAE3B,eAAO,MAAM,0BAA0B;;;;;;CAIA,CAAA;AAyBvC,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,OAAgB,MAAM;;;;;;MAA6B;IAEnD,OAAO,CAAC,eAAe,CAA6B;IAE3C,iBAAiB;IAYjB,oBAAoB;IAM7B,OAAO,CAAC,aAAa;CAmJtB;AAED,eAAO,MAAM,mBAAmB,GAC9B,WAAW,0BAA0B,KACpC,IAIF,CAAA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { defineLumenElement, LumenElement } from '../element-base.js';
|
|
2
|
+
export const lumenComboboxElementConfig = {
|
|
3
|
+
baseClassName: 'ui-combobox',
|
|
4
|
+
defaults: { 'data-ui-combobox': '' },
|
|
5
|
+
tagName: 'lumen-combobox'
|
|
6
|
+
};
|
|
7
|
+
let comboboxId = 0;
|
|
8
|
+
const createComboboxId = () => `ui-combobox-list-${++comboboxId}`;
|
|
9
|
+
const getEventTarget = (event) => {
|
|
10
|
+
const target = event.composedPath()[0] ?? event.target;
|
|
11
|
+
return target instanceof Node ? target : null;
|
|
12
|
+
};
|
|
13
|
+
const getLoopedIndex = (key, currentIndex, itemCount) => {
|
|
14
|
+
if (key === 'Home')
|
|
15
|
+
return 0;
|
|
16
|
+
if (key === 'End')
|
|
17
|
+
return itemCount - 1;
|
|
18
|
+
if (key === 'ArrowDown')
|
|
19
|
+
return (currentIndex + 1) % itemCount;
|
|
20
|
+
return (currentIndex - 1 + itemCount) % itemCount;
|
|
21
|
+
};
|
|
22
|
+
export class LumenComboboxElement extends LumenElement {
|
|
23
|
+
static config = lumenComboboxElementConfig;
|
|
24
|
+
abortController;
|
|
25
|
+
connectedCallback() {
|
|
26
|
+
super.connectedCallback();
|
|
27
|
+
if (typeof document === 'undefined')
|
|
28
|
+
return;
|
|
29
|
+
this.abortController?.abort();
|
|
30
|
+
this.abortController = new AbortController();
|
|
31
|
+
this.setupCombobox(this.abortController.signal);
|
|
32
|
+
}
|
|
33
|
+
disconnectedCallback() {
|
|
34
|
+
this.abortController?.abort();
|
|
35
|
+
this.abortController = undefined;
|
|
36
|
+
}
|
|
37
|
+
setupCombobox(signal) {
|
|
38
|
+
const input = this.querySelector('input[role="combobox"]');
|
|
39
|
+
const listbox = this.querySelector('[role="listbox"]');
|
|
40
|
+
if (!input || !listbox)
|
|
41
|
+
return;
|
|
42
|
+
const items = [...listbox.querySelectorAll('[role="option"]')];
|
|
43
|
+
if (!listbox.id)
|
|
44
|
+
listbox.id = createComboboxId();
|
|
45
|
+
input.setAttribute('aria-autocomplete', input.getAttribute('aria-autocomplete') ?? 'list');
|
|
46
|
+
input.setAttribute('aria-controls', listbox.id);
|
|
47
|
+
const getVisibleItems = () => items.filter(item => (!item.hidden && !item.hasAttribute('disabled') &&
|
|
48
|
+
item.getAttribute('aria-disabled') !== 'true'));
|
|
49
|
+
const close = () => {
|
|
50
|
+
input.setAttribute('aria-expanded', 'false');
|
|
51
|
+
listbox.hidden = true;
|
|
52
|
+
listbox.dataset.state = 'closed';
|
|
53
|
+
};
|
|
54
|
+
const open = () => {
|
|
55
|
+
input.setAttribute('aria-expanded', 'true');
|
|
56
|
+
listbox.hidden = false;
|
|
57
|
+
listbox.dataset.state = 'open';
|
|
58
|
+
};
|
|
59
|
+
const filter = () => {
|
|
60
|
+
const query = input.value.trim().toLowerCase();
|
|
61
|
+
for (const item of items) {
|
|
62
|
+
const value = item.getAttribute('data-value') ?? item.textContent.trim();
|
|
63
|
+
item.hidden = Boolean(query) && !value.toLowerCase().includes(query);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const select = (item) => {
|
|
67
|
+
input.value = item.getAttribute('data-value') ?? item.textContent.trim();
|
|
68
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
69
|
+
input.dispatchEvent(new Event('change', { bubbles: true }));
|
|
70
|
+
input.focus({ preventScroll: true });
|
|
71
|
+
close();
|
|
72
|
+
};
|
|
73
|
+
const focusItem = (item, key) => {
|
|
74
|
+
const visibleItems = getVisibleItems();
|
|
75
|
+
if (!visibleItems.length)
|
|
76
|
+
return;
|
|
77
|
+
const currentIndex = Math.max(0, visibleItems.indexOf(item));
|
|
78
|
+
visibleItems[getLoopedIndex(key, currentIndex, visibleItems.length)]?.focus();
|
|
79
|
+
};
|
|
80
|
+
close();
|
|
81
|
+
input.addEventListener('focus', open, { signal });
|
|
82
|
+
input.addEventListener('input', () => {
|
|
83
|
+
filter();
|
|
84
|
+
open();
|
|
85
|
+
}, { signal });
|
|
86
|
+
input.addEventListener('keydown', event => {
|
|
87
|
+
if (event.key === 'Escape') {
|
|
88
|
+
close();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!['ArrowDown', 'ArrowUp', 'Enter'].includes(event.key))
|
|
92
|
+
return;
|
|
93
|
+
const visibleItems = getVisibleItems();
|
|
94
|
+
if (!visibleItems.length)
|
|
95
|
+
return;
|
|
96
|
+
event.preventDefault();
|
|
97
|
+
open();
|
|
98
|
+
if (event.key === 'Enter') {
|
|
99
|
+
const firstVisibleItem = visibleItems.at(0);
|
|
100
|
+
if (firstVisibleItem)
|
|
101
|
+
select(firstVisibleItem);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const targetIndex = event.key === 'ArrowUp' ? visibleItems.length - 1 : 0;
|
|
105
|
+
visibleItems[targetIndex]?.focus();
|
|
106
|
+
}, { signal });
|
|
107
|
+
for (const item of items) {
|
|
108
|
+
item.tabIndex = -1;
|
|
109
|
+
item.addEventListener('click', () => {
|
|
110
|
+
select(item);
|
|
111
|
+
}, { signal });
|
|
112
|
+
item.addEventListener('keydown', event => {
|
|
113
|
+
if (event.key === 'Escape') {
|
|
114
|
+
close();
|
|
115
|
+
input.focus({ preventScroll: true });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
select(item);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key))
|
|
124
|
+
return;
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
focusItem(item, event.key);
|
|
127
|
+
}, { signal });
|
|
128
|
+
}
|
|
129
|
+
document.addEventListener('pointerdown', event => {
|
|
130
|
+
const target = getEventTarget(event);
|
|
131
|
+
if (target && !this.contains(target))
|
|
132
|
+
close();
|
|
133
|
+
}, { signal });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export const defineLumenCombobox = (registry) => {
|
|
137
|
+
defineLumenElement(lumenComboboxElementConfig, LumenComboboxElement, registry);
|
|
138
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { type LumenCustomElementRegistry } from '../element-base.js';
|
|
2
|
+
export declare const lumenCardContentElementConfig: {
|
|
3
|
+
readonly baseClassName: "ui-card__content";
|
|
4
|
+
readonly defaults: {
|
|
5
|
+
readonly 'data-slot': "card-content";
|
|
6
|
+
};
|
|
7
|
+
readonly tagName: "lumen-card-content";
|
|
8
|
+
};
|
|
9
|
+
export declare const lumenCardDescriptionElementConfig: {
|
|
10
|
+
readonly baseClassName: "ui-card__description";
|
|
11
|
+
readonly defaults: {
|
|
12
|
+
readonly 'data-slot': "card-description";
|
|
13
|
+
};
|
|
14
|
+
readonly tagName: "lumen-card-description";
|
|
15
|
+
};
|
|
16
|
+
export declare const lumenCardFooterElementConfig: {
|
|
17
|
+
readonly baseClassName: "ui-card__footer";
|
|
18
|
+
readonly defaults: {
|
|
19
|
+
readonly 'data-slot': "card-footer";
|
|
20
|
+
};
|
|
21
|
+
readonly tagName: "lumen-card-footer";
|
|
22
|
+
};
|
|
23
|
+
export declare const lumenCardHeaderElementConfig: {
|
|
24
|
+
readonly baseClassName: "ui-card__header";
|
|
25
|
+
readonly defaults: {
|
|
26
|
+
readonly 'data-slot': "card-header";
|
|
27
|
+
};
|
|
28
|
+
readonly tagName: "lumen-card-header";
|
|
29
|
+
};
|
|
30
|
+
export declare const lumenCardTitleElementConfig: {
|
|
31
|
+
readonly baseClassName: "ui-card__title";
|
|
32
|
+
readonly defaults: {
|
|
33
|
+
readonly 'data-slot': "card-title";
|
|
34
|
+
};
|
|
35
|
+
readonly tagName: "lumen-card-title";
|
|
36
|
+
};
|
|
37
|
+
export declare const lumenContainerElementConfig: {
|
|
38
|
+
readonly attributeClasses: {
|
|
39
|
+
readonly size: {
|
|
40
|
+
readonly full: "ui-container--full";
|
|
41
|
+
readonly lg: "ui-container--lg";
|
|
42
|
+
readonly md: "ui-container--md";
|
|
43
|
+
readonly sm: "ui-container--sm";
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
readonly baseClassName: "ui-container";
|
|
47
|
+
readonly defaults: {
|
|
48
|
+
readonly 'data-ui-container': "";
|
|
49
|
+
readonly size: "lg";
|
|
50
|
+
};
|
|
51
|
+
readonly tagName: "lumen-container";
|
|
52
|
+
};
|
|
53
|
+
export declare const lumenDirectionElementConfig: {
|
|
54
|
+
readonly baseClassName: "ui-direction";
|
|
55
|
+
readonly defaults: {
|
|
56
|
+
readonly dir: "ltr";
|
|
57
|
+
};
|
|
58
|
+
readonly tagName: "lumen-direction";
|
|
59
|
+
};
|
|
60
|
+
export declare const lumenGridElementConfig: {
|
|
61
|
+
readonly attributeClasses: {
|
|
62
|
+
readonly columns: {
|
|
63
|
+
readonly 1: "ui-grid--columns-1";
|
|
64
|
+
readonly 2: "ui-grid--columns-2";
|
|
65
|
+
readonly 3: "ui-grid--columns-3";
|
|
66
|
+
readonly 4: "ui-grid--columns-4";
|
|
67
|
+
readonly 6: "ui-grid--columns-6";
|
|
68
|
+
readonly 12: "ui-grid--columns-12";
|
|
69
|
+
readonly auto: "ui-grid--columns-auto";
|
|
70
|
+
};
|
|
71
|
+
readonly gap: {
|
|
72
|
+
readonly lg: "ui-grid--gap-lg";
|
|
73
|
+
readonly md: "ui-grid--gap-md";
|
|
74
|
+
readonly none: "ui-grid--gap-none";
|
|
75
|
+
readonly sm: "ui-grid--gap-sm";
|
|
76
|
+
readonly xl: "ui-grid--gap-xl";
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
readonly baseClassName: "ui-grid";
|
|
80
|
+
readonly defaults: {
|
|
81
|
+
readonly 'data-ui-grid': "";
|
|
82
|
+
readonly columns: "auto";
|
|
83
|
+
readonly gap: "md";
|
|
84
|
+
};
|
|
85
|
+
readonly tagName: "lumen-grid";
|
|
86
|
+
};
|
|
87
|
+
export declare const lumenLabelElementConfig: {
|
|
88
|
+
readonly baseClassName: "ui-label";
|
|
89
|
+
readonly tagName: "lumen-label";
|
|
90
|
+
};
|
|
91
|
+
export declare const lumenSeparatorElementConfig: {
|
|
92
|
+
readonly attributeClasses: {
|
|
93
|
+
readonly orientation: {
|
|
94
|
+
readonly horizontal: "ui-separator--horizontal";
|
|
95
|
+
readonly vertical: "ui-separator--vertical";
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
readonly baseClassName: "ui-separator";
|
|
99
|
+
readonly defaults: {
|
|
100
|
+
readonly orientation: "horizontal";
|
|
101
|
+
};
|
|
102
|
+
readonly tagName: "lumen-separator";
|
|
103
|
+
};
|
|
104
|
+
export declare const lumenSkeletonElementConfig: {
|
|
105
|
+
readonly baseClassName: "ui-skeleton";
|
|
106
|
+
readonly tagName: "lumen-skeleton";
|
|
107
|
+
};
|
|
108
|
+
export declare const lumenSpinnerElementConfig: {
|
|
109
|
+
readonly baseClassName: "ui-spinner";
|
|
110
|
+
readonly tagName: "lumen-spinner";
|
|
111
|
+
};
|
|
112
|
+
export declare const lumenStackElementConfig: {
|
|
113
|
+
readonly attributeClasses: {
|
|
114
|
+
readonly direction: {
|
|
115
|
+
readonly horizontal: "ui-stack--horizontal";
|
|
116
|
+
readonly vertical: "ui-stack--vertical";
|
|
117
|
+
};
|
|
118
|
+
readonly gap: {
|
|
119
|
+
readonly lg: "ui-stack--gap-lg";
|
|
120
|
+
readonly md: "ui-stack--gap-md";
|
|
121
|
+
readonly none: "ui-stack--gap-none";
|
|
122
|
+
readonly sm: "ui-stack--gap-sm";
|
|
123
|
+
readonly xl: "ui-stack--gap-xl";
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
readonly baseClassName: "ui-stack";
|
|
127
|
+
readonly defaults: {
|
|
128
|
+
readonly 'data-ui-stack': "";
|
|
129
|
+
readonly direction: "vertical";
|
|
130
|
+
readonly gap: "md";
|
|
131
|
+
};
|
|
132
|
+
readonly tagName: "lumen-stack";
|
|
133
|
+
};
|
|
134
|
+
export declare const lumenTypographyElementConfig: {
|
|
135
|
+
readonly baseClassName: "ui-typography";
|
|
136
|
+
readonly tagName: "lumen-typography";
|
|
137
|
+
};
|
|
138
|
+
export declare const lumenVisuallyHiddenElementConfig: {
|
|
139
|
+
readonly baseClassName: "ui-visually-hidden";
|
|
140
|
+
readonly defaults: {
|
|
141
|
+
readonly 'data-ui-visually-hidden': "";
|
|
142
|
+
};
|
|
143
|
+
readonly tagName: "lumen-visually-hidden";
|
|
144
|
+
};
|
|
145
|
+
export declare const LumenCardContentElement: import("../element-base.js").LumenElementConstructor;
|
|
146
|
+
export declare const LumenCardDescriptionElement: import("../element-base.js").LumenElementConstructor;
|
|
147
|
+
export declare const LumenCardFooterElement: import("../element-base.js").LumenElementConstructor;
|
|
148
|
+
export declare const LumenCardHeaderElement: import("../element-base.js").LumenElementConstructor;
|
|
149
|
+
export declare const LumenCardTitleElement: import("../element-base.js").LumenElementConstructor;
|
|
150
|
+
export declare const LumenContainerElement: import("../element-base.js").LumenElementConstructor;
|
|
151
|
+
export declare const LumenDirectionElement: import("../element-base.js").LumenElementConstructor;
|
|
152
|
+
export declare const LumenGridElement: import("../element-base.js").LumenElementConstructor;
|
|
153
|
+
export declare const LumenLabelElement: import("../element-base.js").LumenElementConstructor;
|
|
154
|
+
export declare const LumenSeparatorElement: import("../element-base.js").LumenElementConstructor;
|
|
155
|
+
export declare const LumenSkeletonElement: import("../element-base.js").LumenElementConstructor;
|
|
156
|
+
export declare const LumenSpinnerElement: import("../element-base.js").LumenElementConstructor;
|
|
157
|
+
export declare const LumenStackElement: import("../element-base.js").LumenElementConstructor;
|
|
158
|
+
export declare const LumenTypographyElement: import("../element-base.js").LumenElementConstructor;
|
|
159
|
+
export declare const LumenVisuallyHiddenElement: import("../element-base.js").LumenElementConstructor;
|
|
160
|
+
export declare const defineLumenFoundations: (registry?: LumenCustomElementRegistry) => void;
|
|
161
|
+
//# sourceMappingURL=foundations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foundations.d.ts","sourceRoot":"","sources":["../../src/components/foundations.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,0BAA0B,EAEhC,MAAM,oBAAoB,CAAA;AAO3B,eAAO,MAAM,6BAA6B;;;;;;CAIH,CAAA;AAEvC,eAAO,MAAM,iCAAiC;;;;;;CAIP,CAAA;AAEvC,eAAO,MAAM,4BAA4B;;;;;;CAIF,CAAA;AAEvC,eAAO,MAAM,4BAA4B;;;;;;CAIF,CAAA;AAEvC,eAAO,MAAM,2BAA2B;;;;;;CAID,CAAA;AAEvC,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;CAYD,CAAA;AAEvC,eAAO,MAAM,2BAA2B;;;;;;CAID,CAAA;AAEvC,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;CAsBI,CAAA;AAEvC,eAAO,MAAM,uBAAuB;;;CAGG,CAAA;AAEvC,eAAO,MAAM,2BAA2B;;;;;;;;;;;;CAUD,CAAA;AAEvC,eAAO,MAAM,0BAA0B;;;CAGA,CAAA;AAEvC,eAAO,MAAM,yBAAyB;;;CAGC,CAAA;AAEvC,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;CAiBG,CAAA;AAEvC,eAAO,MAAM,4BAA4B;;;CAGF,CAAA;AAEvC,eAAO,MAAM,gCAAgC;;;;;;CAIN,CAAA;AAkBvC,eAAO,MAAM,uBAAuB,sDAAsB,CAAA;AAC1D,eAAO,MAAM,2BAA2B,sDAA0B,CAAA;AAClE,eAAO,MAAM,sBAAsB,sDAAqB,CAAA;AACxD,eAAO,MAAM,sBAAsB,sDAAqB,CAAA;AACxD,eAAO,MAAM,qBAAqB,sDAAoB,CAAA;AACtD,eAAO,MAAM,qBAAqB,sDAAoB,CAAA;AACtD,eAAO,MAAM,qBAAqB,sDAAoB,CAAA;AACtD,eAAO,MAAM,gBAAgB,sDAAe,CAAA;AAC5C,eAAO,MAAM,iBAAiB,sDAAgB,CAAA;AAC9C,eAAO,MAAM,qBAAqB,sDAAoB,CAAA;AACtD,eAAO,MAAM,oBAAoB,sDAAmB,CAAA;AACpD,eAAO,MAAM,mBAAmB,sDAAkB,CAAA;AAClD,eAAO,MAAM,iBAAiB,sDAAgB,CAAA;AAC9C,eAAO,MAAM,sBAAsB,sDAAqB,CAAA;AACxD,eAAO,MAAM,0BAA0B,sDAAyB,CAAA;AAoBhE,eAAO,MAAM,sBAAsB,GACjC,WAAW,0BAA0B,KACpC,IAIF,CAAA"}
|