@rcarls/rc-toolbar 0.2.0 → 0.3.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 +12 -8
- package/dist/custom-elements.json +6 -1
- package/dist/{rc-toolbar-D7nv57AW.js → rc-toolbar-BPcEdxN8.js} +18 -17
- package/dist/rc-toolbar-BPcEdxN8.js.map +1 -0
- package/dist/rc-toolbar-define.js +1 -1
- package/dist/rc-toolbar.js +1 -1
- package/dist/types/packages/rc-toolbar/src/rc-toolbar.d.ts +6 -2
- package/package.json +7 -10
- package/dist/demo.css +0 -85
- package/dist/demo.js +0 -40
- package/dist/rc-toolbar-D7nv57AW.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# `@rcarls/rc-toolbar`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Toolbar that groups consumer-supplied controls into one tab stop with arrow-key navigation, following the [WAI-ARIA Toolbar pattern](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/).
|
|
4
|
+
|
|
5
|
+
Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-toolbar](https://richardcarls.github.io/rc-webcomponents/components/rc-toolbar).
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
@@ -52,28 +54,30 @@ Vertical orientation:
|
|
|
52
54
|
### Properties / attributes
|
|
53
55
|
|
|
54
56
|
| Property | Attribute | Type | Default | Description |
|
|
55
|
-
|
|
57
|
+
| --- | --- | --- | --- | --- |
|
|
56
58
|
| `label` | `label` | `string` | `'Toolbar'` | `aria-label` for the toolbar. Required — no visible label is rendered by the component. |
|
|
57
59
|
| `orientation` | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout direction and keyboard navigation axis. |
|
|
58
60
|
|
|
59
61
|
### CSS custom properties
|
|
60
62
|
|
|
61
63
|
| Property | Default | Description |
|
|
62
|
-
|
|
64
|
+
| --- | --- | --- |
|
|
63
65
|
| `--rc-toolbar-gap-inline` | `0.25em` | Gap between toolbar items |
|
|
64
66
|
| `--rc-toolbar-padding-inline` | `0.25em` | Horizontal padding on the toolbar container |
|
|
65
67
|
| `--rc-toolbar-padding-block` | `0.125em` | Vertical padding on the toolbar container |
|
|
68
|
+
| `--rc-toolbar-radius` | `var(--rc-control-radius)` | Toolbar container border radius |
|
|
69
|
+
| `--rc-toolbar-vertical-radius` | `var(--rc-toolbar-radius)` | Border radius override for vertical orientation |
|
|
66
70
|
|
|
67
71
|
### CSS parts
|
|
68
72
|
|
|
69
|
-
| Part
|
|
70
|
-
|
|
73
|
+
| Part | Element | Description |
|
|
74
|
+
| --- | --- | --- |
|
|
71
75
|
| `root` | `div[role="toolbar"]` | The toolbar container element |
|
|
72
76
|
|
|
73
77
|
### Slots
|
|
74
78
|
|
|
75
79
|
| Slot | Description |
|
|
76
|
-
|
|
80
|
+
| --- | --- |
|
|
77
81
|
| *(default)* | Toolbar controls. Focusable elements (`<button>`, `<input>`, `<select>`, `<a href>`, elements with `tabindex`) participate in roving-tabindex navigation. All others are rendered but skipped. |
|
|
78
82
|
|
|
79
83
|
### Events
|
|
@@ -107,7 +111,7 @@ previousItem: HTMLElement | undefined
|
|
|
107
111
|
The toolbar is a single tab stop. Arrow keys navigate within it.
|
|
108
112
|
|
|
109
113
|
| Key | Orientation | Action |
|
|
110
|
-
|
|
114
|
+
| --- | --- | --- |
|
|
111
115
|
| `ArrowRight` | Horizontal | Focus next item (wraps) |
|
|
112
116
|
| `ArrowLeft` | Horizontal | Focus previous item (wraps) |
|
|
113
117
|
| `ArrowDown` | Vertical | Focus next item (wraps) |
|
|
@@ -121,7 +125,7 @@ The toolbar is a single tab stop. Arrow keys navigate within it.
|
|
|
121
125
|
## ARIA
|
|
122
126
|
|
|
123
127
|
| Attribute | Where | Value |
|
|
124
|
-
|
|
128
|
+
| --- | --- | --- |
|
|
125
129
|
| `role="toolbar"` | Root `div` | — |
|
|
126
130
|
| `aria-orientation` | Root `div` | `"horizontal"` or `"vertical"` |
|
|
127
131
|
| `aria-label` | Root `div` | Value of `label` property |
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"declarations": [
|
|
47
47
|
{
|
|
48
48
|
"kind": "class",
|
|
49
|
-
"description": "
|
|
49
|
+
"description": "Toolbar that groups consumer-supplied controls into one tab stop with arrow-key\nnavigation, following the WAI-ARIA Toolbar pattern.",
|
|
50
50
|
"name": "RCToolbar",
|
|
51
51
|
"cssProperties": [
|
|
52
52
|
{
|
|
@@ -68,6 +68,11 @@
|
|
|
68
68
|
"description": "Toolbar container border radius",
|
|
69
69
|
"name": "--rc-toolbar-radius",
|
|
70
70
|
"default": "var(--rc-control-radius)"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"description": "Toolbar container border radius when orientation is vertical; falls back to `--rc-toolbar-radius`",
|
|
74
|
+
"name": "--rc-toolbar-vertical-radius",
|
|
75
|
+
"default": "var(--rc-toolbar-radius)"
|
|
71
76
|
}
|
|
72
77
|
],
|
|
73
78
|
"cssParts": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { css as u, LitElement as
|
|
1
|
+
import { css as u, LitElement as b, html as h } from "lit";
|
|
2
2
|
import { property as d, query as f } from "lit/decorators.js";
|
|
3
|
-
import { RovingTabIndexMixin as m, isFocusable as l, keyNavigation as p } from "@rcarls/rc-common";
|
|
4
|
-
const
|
|
3
|
+
import { RovingTabIndexMixin as m, isFocusable as l, keyNavigation as p, keyInteraction as v } from "@rcarls/rc-common";
|
|
4
|
+
const g = u`
|
|
5
5
|
:host {
|
|
6
6
|
display: inline-block;
|
|
7
7
|
}
|
|
@@ -19,6 +19,7 @@ const v = u`
|
|
|
19
19
|
|
|
20
20
|
&[aria-orientation='vertical'] {
|
|
21
21
|
flex-direction: column;
|
|
22
|
+
border-radius: var(--rc-toolbar-vertical-radius, var(--rc-toolbar-radius, var(--rc-control-radius, 0)));
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/* because :has(:focus-visible) doens't work across slot boundary */
|
|
@@ -32,12 +33,12 @@ const v = u`
|
|
|
32
33
|
display: contents;
|
|
33
34
|
}
|
|
34
35
|
`;
|
|
35
|
-
var
|
|
36
|
-
for (var
|
|
37
|
-
(c =
|
|
38
|
-
return
|
|
36
|
+
var _ = Object.defineProperty, s = (n, t, e, y) => {
|
|
37
|
+
for (var r = void 0, o = n.length - 1, c; o >= 0; o--)
|
|
38
|
+
(c = n[o]) && (r = c(t, e, r) || r);
|
|
39
|
+
return r && _(t, e, r), r;
|
|
39
40
|
};
|
|
40
|
-
const
|
|
41
|
+
const a = class a extends m(b) {
|
|
41
42
|
constructor() {
|
|
42
43
|
super(...arguments), this.label = "Toolbar", this.orientation = "horizontal", this._disabledObserver = new MutationObserver(() => this._syncTabStop());
|
|
43
44
|
}
|
|
@@ -85,12 +86,12 @@ const n = class n extends m(h) {
|
|
|
85
86
|
return e === "button" || e === "checkbox" || e === "link" || e === "menuitem" || e === "radio" || e === "slider" || e === "spinbutton" || e === "switch" || e === "textbox" ? !0 : l(t);
|
|
86
87
|
}
|
|
87
88
|
render() {
|
|
88
|
-
return
|
|
89
|
+
return h`
|
|
89
90
|
<div
|
|
90
91
|
id="root"
|
|
91
92
|
part="root"
|
|
92
93
|
${p(this._onNavigate)}
|
|
93
|
-
|
|
94
|
+
${v()}
|
|
94
95
|
role="toolbar"
|
|
95
96
|
aria-orientation=${this.orientation}
|
|
96
97
|
aria-label=${this.label}
|
|
@@ -102,18 +103,18 @@ const n = class n extends m(h) {
|
|
|
102
103
|
`;
|
|
103
104
|
}
|
|
104
105
|
};
|
|
105
|
-
|
|
106
|
-
let
|
|
106
|
+
a.styles = [g];
|
|
107
|
+
let i = a;
|
|
107
108
|
s([
|
|
108
109
|
d({ type: String })
|
|
109
|
-
],
|
|
110
|
+
], i.prototype, "label");
|
|
110
111
|
s([
|
|
111
112
|
d({ type: String })
|
|
112
|
-
],
|
|
113
|
+
], i.prototype, "orientation");
|
|
113
114
|
s([
|
|
114
115
|
f("#root", !0)
|
|
115
|
-
],
|
|
116
|
+
], i.prototype, "_$root");
|
|
116
117
|
export {
|
|
117
|
-
|
|
118
|
+
i as R
|
|
118
119
|
};
|
|
119
|
-
//# sourceMappingURL=rc-toolbar-
|
|
120
|
+
//# sourceMappingURL=rc-toolbar-BPcEdxN8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-toolbar-BPcEdxN8.js","sources":["../src/rc-toolbar.styles.ts","../src/rc-toolbar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const toolbarStyles = css`\n :host {\n display: inline-block;\n }\n\n #root {\n display: flex;\n flex-direction: row;\n gap: var(--rc-toolbar-gap-inline, var(--rc-control-gap, 0.25em));\n padding-inline: var(--rc-toolbar-padding-inline, calc(var(--rc-control-padding-inline, 0.5em) / 2));\n padding-block: var(--rc-toolbar-padding-block, calc(var(--rc-control-padding-block, 0.25em) / 2));\n border-radius: var(--rc-toolbar-radius, var(--rc-control-radius, 0));\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n\n &[aria-orientation='vertical'] {\n flex-direction: column;\n border-radius: var(--rc-toolbar-vertical-radius, var(--rc-toolbar-radius, var(--rc-control-radius, 0)));\n }\n\n /* because :has(:focus-visible) doens't work across slot boundary */\n &[data-interaction-mode='keyboard']:focus-within {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n }\n\n #slot-wrap {\n display: contents;\n }\n`;\n\nexport default toolbarStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query } from 'lit/decorators.js';\n\nimport {\n isFocusable,\n keyInteraction,\n keyNavigation,\n type KeyboardNavigationAction,\n RovingTabIndexMixin,\n} from '@rcarls/rc-common';\n\nimport toolbarStyles from './rc-toolbar.styles';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-toolbar': RCToolbar;\n }\n}\n\n/**\n * Toolbar that groups consumer-supplied controls into one tab stop with arrow-key\n * navigation, following the WAI-ARIA Toolbar pattern.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-toolbar rc-toolbar docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/ WAI-ARIA Toolbar pattern}\n *\n * @slot Takes any number of child elements to display in the toolbar. Only focusable elements are navigable.\n * @cssprop [--rc-toolbar-gap-inline=0.25em] - Gap between toolbar items\n * @cssprop [--rc-toolbar-padding-inline=calc(var(--rc-control-padding-inline) / 2)] - Horizontal padding on the toolbar container\n * @cssprop [--rc-toolbar-padding-block=calc(var(--rc-control-padding-block) / 2)] - Vertical padding on the toolbar container\n * @cssprop [--rc-toolbar-radius=var(--rc-control-radius)] - Toolbar container border radius\n * @cssprop [--rc-toolbar-vertical-radius=var(--rc-toolbar-radius)] - Toolbar container border radius when orientation is vertical; falls back to `--rc-toolbar-radius`\n * @csspart root - The toolbar container element\n */\nexport class RCToolbar extends RovingTabIndexMixin(LitElement) {\n static styles = [toolbarStyles];\n\n /** Accessible label for this toolbar. Default label is 'Toolbar'. */\n @property({ type: String })\n label = 'Toolbar';\n\n /** Toolbar orientation, for keyboard navigation. */\n @property({ type: String })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n private readonly _disabledObserver = new MutationObserver(() => this._syncTabStop());\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._disabledObserver.observe(this, { attributeFilter: ['disabled'], subtree: true });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._disabledObserver.disconnect();\n }\n\n private _syncTabStop(): void {\n if (!this._lastFocused || isFocusable(this._lastFocused)) return;\n this._lastFocused = undefined;\n this._initItems();\n }\n\n protected override _initItems() {\n // Set tabindex synchronously so items are in the tab order immediately,\n // even if the document has no focus yet (focus() would be a no-op).\n super._initItems();\n\n // Defer focus to avoid firing focusin/focusout inside a SolidJS reactive\n // update cycle, which can cause the update to hang.\n // Guard: only restore focus when the toolbar already contains it — prevents\n // focus-stealing when a toolbar mounts inside a larger component (e.g. rc-transfer-list).\n const target = this._lastFocused ?? this.firstItem;\n queueMicrotask(() => {\n if (this.matches(':focus-within')) this.focusItem(target);\n });\n }\n\n protected _onNavigate(action: KeyboardNavigationAction) {\n switch (action) {\n case 'next':\n this.focusItem(this.nextItem);\n break;\n case 'prev':\n this.focusItem(this.previousItem);\n break;\n case 'start':\n this.focusItem(this.firstItem);\n break;\n case 'end':\n this.focusItem(this.lastItem);\n break;\n }\n }\n\n protected override _collectItems(slot: HTMLSlotElement): Element[] {\n return slot.assignedElements().filter((el) => this._isToolbarItem(el));\n }\n\n private _isToolbarItem(el: Element): boolean {\n if (\n el instanceof HTMLButtonElement ||\n el instanceof HTMLInputElement ||\n el instanceof HTMLSelectElement ||\n el instanceof HTMLTextAreaElement\n ) {\n return true;\n }\n\n if (el instanceof HTMLAnchorElement || el instanceof HTMLAreaElement) {\n return el.hasAttribute('href');\n }\n\n const role = el.getAttribute('role');\n if (\n role === 'button' ||\n role === 'checkbox' ||\n role === 'link' ||\n role === 'menuitem' ||\n role === 'radio' ||\n role === 'slider' ||\n role === 'spinbutton' ||\n role === 'switch' ||\n role === 'textbox'\n ) {\n return true;\n }\n\n return isFocusable(el);\n }\n\n protected render() {\n return html`\n <div\n id=\"root\"\n part=\"root\"\n ${keyNavigation(this._onNavigate)}\n ${keyInteraction()}\n role=\"toolbar\"\n aria-orientation=${this.orientation}\n aria-label=${this.label}\n >\n <div id=\"slot-wrap\" @focusin=${this._handleItemFocus}>\n <slot id=\"items\" @slotchange=${this._onSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\nexport default RCToolbar;\n"],"names":["toolbarStyles","css","_RCToolbar","RovingTabIndexMixin","LitElement","isFocusable","target","action","slot","el","role","html","keyNavigation","keyInteraction","RCToolbar","__decorateClass","property","query"],"mappings":";;;AAEO,MAAMA,IAAgBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACgCtB,MAAMC,IAAN,MAAMA,UAAkBC,EAAoBC,CAAU,EAAE;AAAA,EAAxD,cAAA;AAAA,UAAA,GAAA,SAAA,GAKL,KAAA,QAAQ,WAIR,KAAA,cAAyC,cAKzC,KAAiB,oBAAoB,IAAI,iBAAiB,MAAM,KAAK,cAAc;AAAA,EAAA;AAAA,EAE1E,oBAA0B;AACjC,UAAM,kBAAA,GACN,KAAK,kBAAkB,QAAQ,MAAM,EAAE,iBAAiB,CAAC,UAAU,GAAG,SAAS,IAAM;AAAA,EACvF;AAAA,EAES,uBAA6B;AACpC,UAAM,qBAAA,GACN,KAAK,kBAAkB,WAAA;AAAA,EACzB;AAAA,EAEQ,eAAqB;AAC3B,IAAI,CAAC,KAAK,gBAAgBC,EAAY,KAAK,YAAY,MACvD,KAAK,eAAe,QACpB,KAAK,WAAA;AAAA,EACP;AAAA,EAEmB,aAAa;AAG9B,UAAM,WAAA;AAMN,UAAMC,IAAS,KAAK,gBAAgB,KAAK;AACzC,mBAAe,MAAM;AACnB,MAAI,KAAK,QAAQ,eAAe,KAAG,KAAK,UAAUA,CAAM;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EAEU,YAAYC,GAAkC;AACtD,YAAQA,GAAA;AAAA,MACN,KAAK;AACH,aAAK,UAAU,KAAK,QAAQ;AAC5B;AAAA,MACF,KAAK;AACH,aAAK,UAAU,KAAK,YAAY;AAChC;AAAA,MACF,KAAK;AACH,aAAK,UAAU,KAAK,SAAS;AAC7B;AAAA,MACF,KAAK;AACH,aAAK,UAAU,KAAK,QAAQ;AAC5B;AAAA,IAAA;AAAA,EAEN;AAAA,EAEmB,cAAcC,GAAkC;AACjE,WAAOA,EAAK,mBAAmB,OAAO,CAACC,MAAO,KAAK,eAAeA,CAAE,CAAC;AAAA,EACvE;AAAA,EAEQ,eAAeA,GAAsB;AAC3C,QACEA,aAAc,qBACdA,aAAc,oBACdA,aAAc,qBACdA,aAAc;AAEd,aAAO;AAGT,QAAIA,aAAc,qBAAqBA,aAAc;AACnD,aAAOA,EAAG,aAAa,MAAM;AAG/B,UAAMC,IAAOD,EAAG,aAAa,MAAM;AACnC,WACEC,MAAS,YACTA,MAAS,cACTA,MAAS,UACTA,MAAS,cACTA,MAAS,WACTA,MAAS,YACTA,MAAS,gBACTA,MAAS,YACTA,MAAS,YAEF,KAGFL,EAAYI,CAAE;AAAA,EACvB;AAAA,EAEU,SAAS;AACjB,WAAOE;AAAA;AAAA;AAAA;AAAA,UAIDC,EAAc,KAAK,WAAW,CAAC;AAAA,UAC/BC,GAAgB;AAAA;AAAA,2BAEC,KAAK,WAAW;AAAA,qBACtB,KAAK,KAAK;AAAA;AAAA,uCAEQ,KAAK,gBAAgB;AAAA,yCACnB,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA,EAIzD;AACF;AApHEX,EAAO,SAAS,CAACF,CAAa;AADzB,IAAMc,IAANZ;AAKLa,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAJfF,EAKX,WAAA,OAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfF,EASX,WAAA,aAAA;AAGUC,EAAA;AAAA,EADTE,EAAM,SAAS,EAAI;AAAA,GAXTH,EAYD,WAAA,QAAA;"}
|
package/dist/rc-toolbar.js
CHANGED
|
@@ -7,14 +7,18 @@ declare global {
|
|
|
7
7
|
}
|
|
8
8
|
declare const RCToolbar_base: typeof LitElement & (new (...args: any[]) => import('@rcarls/rc-common').RovingTabIndexMixinBase);
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Toolbar that groups consumer-supplied controls into one tab stop with arrow-key
|
|
11
|
+
* navigation, following the WAI-ARIA Toolbar pattern.
|
|
12
|
+
*
|
|
13
|
+
* @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-toolbar rc-toolbar docs}
|
|
14
|
+
* @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/ WAI-ARIA Toolbar pattern}
|
|
11
15
|
*
|
|
12
|
-
* @see https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/
|
|
13
16
|
* @slot Takes any number of child elements to display in the toolbar. Only focusable elements are navigable.
|
|
14
17
|
* @cssprop [--rc-toolbar-gap-inline=0.25em] - Gap between toolbar items
|
|
15
18
|
* @cssprop [--rc-toolbar-padding-inline=calc(var(--rc-control-padding-inline) / 2)] - Horizontal padding on the toolbar container
|
|
16
19
|
* @cssprop [--rc-toolbar-padding-block=calc(var(--rc-control-padding-block) / 2)] - Vertical padding on the toolbar container
|
|
17
20
|
* @cssprop [--rc-toolbar-radius=var(--rc-control-radius)] - Toolbar container border radius
|
|
21
|
+
* @cssprop [--rc-toolbar-vertical-radius=var(--rc-toolbar-radius)] - Toolbar container border radius when orientation is vertical; falls back to `--rc-toolbar-radius`
|
|
18
22
|
* @csspart root - The toolbar container element
|
|
19
23
|
*/
|
|
20
24
|
export declare class RCToolbar extends RCToolbar_base {
|
package/package.json
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
7
|
-
"description": "
|
|
6
|
+
"version": "0.3.0",
|
|
7
|
+
"description": "Toolbar that groups consumer-supplied controls into one tab stop with arrow-key navigation.",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/richardcarls/rc-webcomponents.git",
|
|
11
11
|
"directory": "packages/rc-toolbar"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://github.
|
|
13
|
+
"homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-toolbar",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"files": [
|
|
@@ -37,21 +37,18 @@
|
|
|
37
37
|
],
|
|
38
38
|
"customElements": "dist/custom-elements.json",
|
|
39
39
|
"scripts": {
|
|
40
|
-
"dev": "vite",
|
|
41
40
|
"build": "tsc && vite build && cem analyze",
|
|
42
41
|
"cem:analyze": "cem analyze",
|
|
43
42
|
"preview": "vite preview",
|
|
44
|
-
"test:browser": "vitest",
|
|
45
|
-
"test:browser:chrome": "vitest --project=chromium",
|
|
46
|
-
"test:browser:firefox": "vitest --project=firefox"
|
|
47
|
-
"yalc:publish": "yalc publish --push"
|
|
43
|
+
"test:browser": "vitest --run",
|
|
44
|
+
"test:browser:chrome": "vitest --run --project=chromium",
|
|
45
|
+
"test:browser:firefox": "vitest --run --project=firefox"
|
|
48
46
|
},
|
|
49
47
|
"dependencies": {
|
|
50
|
-
"@rcarls/rc-common": "workspace
|
|
48
|
+
"@rcarls/rc-common": "workspace:*"
|
|
51
49
|
},
|
|
52
50
|
"devDependencies": {
|
|
53
51
|
"@custom-elements-manifest/analyzer": "0.11.0",
|
|
54
|
-
"@guanghechen/rollup-plugin-copy": "^6.0.9",
|
|
55
52
|
"@vitest/browser-playwright": "4.1.5",
|
|
56
53
|
"lit": "^3.0.0",
|
|
57
54
|
"playwright": "^1.56.0",
|
package/dist/demo.css
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
*, *::before, *::after {
|
|
2
|
-
box-sizing: border-box;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
:root {
|
|
6
|
-
color-scheme: light dark;
|
|
7
|
-
--rc-accent: Highlight; /* Chrome doesn't support AccentColor on the open web */
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
@supports (color: AccentColor) {
|
|
11
|
-
:root {
|
|
12
|
-
--rc-accent: AccentColor;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
[data-theme="light"] { color-scheme: light; }
|
|
17
|
-
[data-theme="dark"] { color-scheme: dark; }
|
|
18
|
-
|
|
19
|
-
[data-theme="solarized-light"] {
|
|
20
|
-
color-scheme: light;
|
|
21
|
-
--rc-surface: #fdf6e3;
|
|
22
|
-
--rc-text: #657b83;
|
|
23
|
-
--rc-border: 1px solid #93a1a1;
|
|
24
|
-
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .12);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
[data-theme="solarized-dark"] {
|
|
28
|
-
color-scheme: dark;
|
|
29
|
-
--rc-surface: #002b36;
|
|
30
|
-
--rc-text: #839496;
|
|
31
|
-
--rc-border: 1px solid #586e75;
|
|
32
|
-
--rc-shadow: 0 2px 8px rgba(0, 0, 0, .3);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
body {
|
|
36
|
-
font-family: system-ui, sans-serif;
|
|
37
|
-
margin: 0;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.demo-page {
|
|
41
|
-
max-width: 60rem;
|
|
42
|
-
margin: 0 auto;
|
|
43
|
-
padding: 2rem 1.5rem;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.demo-controls {
|
|
47
|
-
display: flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
gap: 1rem;
|
|
50
|
-
margin-bottom: 2rem;
|
|
51
|
-
padding-bottom: 1rem;
|
|
52
|
-
border-bottom: 1px solid ButtonBorder;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.demo-controls .demo-title {
|
|
56
|
-
flex: 1;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.demo-controls h1 {
|
|
60
|
-
margin: 0 0 0.15rem;
|
|
61
|
-
font-size: 1.5rem;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.demo-controls a {
|
|
65
|
-
font-size: 0.8rem;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.demo-section {
|
|
69
|
-
margin-bottom: 2rem;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.demo-section h2 {
|
|
73
|
-
margin: 0 0 0.5rem;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.theme-picker {
|
|
77
|
-
padding: 0.35em 0.75em;
|
|
78
|
-
font-family: inherit;
|
|
79
|
-
font-size: 0.8rem;
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
border: 1px solid ButtonBorder;
|
|
82
|
-
border-radius: 4px;
|
|
83
|
-
background: Canvas;
|
|
84
|
-
color: CanvasText;
|
|
85
|
-
}
|
package/dist/demo.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const THEMES = ['', 'light', 'dark', 'solarized-light', 'solarized-dark'];
|
|
2
|
-
const LABELS = ['Auto', 'Light', 'Dark', 'Solarized ☀', 'Solarized ☾'];
|
|
3
|
-
|
|
4
|
-
const stored = localStorage.getItem('rc-demo-theme') ?? '';
|
|
5
|
-
applyTheme(stored);
|
|
6
|
-
|
|
7
|
-
function applyTheme(theme) {
|
|
8
|
-
if (theme) {
|
|
9
|
-
document.documentElement.dataset.theme = theme;
|
|
10
|
-
} else {
|
|
11
|
-
delete document.documentElement.dataset.theme;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function currentIndex() {
|
|
16
|
-
const current = document.documentElement.dataset.theme ?? '';
|
|
17
|
-
const idx = THEMES.indexOf(current);
|
|
18
|
-
return idx === -1 ? 0 : idx;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function updateButtons() {
|
|
22
|
-
const label = LABELS[currentIndex()];
|
|
23
|
-
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
24
|
-
btn.textContent = label;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
window.cycleTheme = function () {
|
|
29
|
-
const next = THEMES[(currentIndex() + 1) % THEMES.length];
|
|
30
|
-
applyTheme(next);
|
|
31
|
-
localStorage.setItem('rc-demo-theme', next);
|
|
32
|
-
updateButtons();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
36
|
-
updateButtons();
|
|
37
|
-
document.querySelectorAll('.theme-picker').forEach((btn) => {
|
|
38
|
-
btn.addEventListener('click', window.cycleTheme);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rc-toolbar-D7nv57AW.js","sources":["../src/rc-toolbar.styles.ts","../src/rc-toolbar.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const toolbarStyles = css`\n :host {\n display: inline-block;\n }\n\n #root {\n display: flex;\n flex-direction: row;\n gap: var(--rc-toolbar-gap-inline, var(--rc-control-gap, 0.25em));\n padding-inline: var(--rc-toolbar-padding-inline, calc(var(--rc-control-padding-inline, 0.5em) / 2));\n padding-block: var(--rc-toolbar-padding-block, calc(var(--rc-control-padding-block, 0.25em) / 2));\n border-radius: var(--rc-toolbar-radius, var(--rc-control-radius, 0));\n font-family: var(--rc-font-family, inherit);\n font-size: var(--rc-font-size, inherit);\n line-height: var(--rc-line-height, normal);\n\n &[aria-orientation='vertical'] {\n flex-direction: column;\n }\n\n /* because :has(:focus-visible) doens't work across slot boundary */\n &[data-interaction-mode='keyboard']:focus-within {\n outline: var(--rc-focus-ring, auto);\n outline-offset: var(--rc-focus-ring-offset, 0);\n }\n }\n\n #slot-wrap {\n display: contents;\n }\n`;\n\nexport default toolbarStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query } from 'lit/decorators.js';\n\nimport {\n isFocusable,\n keyNavigation,\n type KeyboardNavigationAction,\n RovingTabIndexMixin,\n} from '@rcarls/rc-common';\n\nimport toolbarStyles from './rc-toolbar.styles';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-toolbar': RCToolbar;\n }\n}\n\n/**\n * A toolbar component, as defined in WAI-ARIA\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/\n * @slot Takes any number of child elements to display in the toolbar. Only focusable elements are navigable.\n * @cssprop [--rc-toolbar-gap-inline=0.25em] - Gap between toolbar items\n * @cssprop [--rc-toolbar-padding-inline=calc(var(--rc-control-padding-inline) / 2)] - Horizontal padding on the toolbar container\n * @cssprop [--rc-toolbar-padding-block=calc(var(--rc-control-padding-block) / 2)] - Vertical padding on the toolbar container\n * @cssprop [--rc-toolbar-radius=var(--rc-control-radius)] - Toolbar container border radius\n * @csspart root - The toolbar container element\n */\nexport class RCToolbar extends RovingTabIndexMixin(LitElement) {\n static styles = [toolbarStyles];\n\n /** Accessible label for this toolbar. Default label is 'Toolbar'. */\n @property({ type: String })\n label = 'Toolbar';\n\n /** Toolbar orientation, for keyboard navigation. */\n @property({ type: String })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n private readonly _disabledObserver = new MutationObserver(() => this._syncTabStop());\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._disabledObserver.observe(this, { attributeFilter: ['disabled'], subtree: true });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._disabledObserver.disconnect();\n }\n\n private _syncTabStop(): void {\n if (!this._lastFocused || isFocusable(this._lastFocused)) return;\n this._lastFocused = undefined;\n this._initItems();\n }\n\n protected override _initItems() {\n // Set tabindex synchronously so items are in the tab order immediately,\n // even if the document has no focus yet (focus() would be a no-op).\n super._initItems();\n\n // Defer focus to avoid firing focusin/focusout inside a SolidJS reactive\n // update cycle, which can cause the update to hang.\n // Guard: only restore focus when the toolbar already contains it — prevents\n // focus-stealing when a toolbar mounts inside a larger component (e.g. rc-transfer-list).\n const target = this._lastFocused ?? this.firstItem;\n queueMicrotask(() => {\n if (this.matches(':focus-within')) this.focusItem(target);\n });\n }\n\n protected _onNavigate(action: KeyboardNavigationAction) {\n switch (action) {\n case 'next':\n this.focusItem(this.nextItem);\n break;\n case 'prev':\n this.focusItem(this.previousItem);\n break;\n case 'start':\n this.focusItem(this.firstItem);\n break;\n case 'end':\n this.focusItem(this.lastItem);\n break;\n }\n }\n\n protected override _collectItems(slot: HTMLSlotElement): Element[] {\n return slot.assignedElements().filter((el) => this._isToolbarItem(el));\n }\n\n private _isToolbarItem(el: Element): boolean {\n if (\n el instanceof HTMLButtonElement ||\n el instanceof HTMLInputElement ||\n el instanceof HTMLSelectElement ||\n el instanceof HTMLTextAreaElement\n ) {\n return true;\n }\n\n if (el instanceof HTMLAnchorElement || el instanceof HTMLAreaElement) {\n return el.hasAttribute('href');\n }\n\n const role = el.getAttribute('role');\n if (\n role === 'button' ||\n role === 'checkbox' ||\n role === 'link' ||\n role === 'menuitem' ||\n role === 'radio' ||\n role === 'slider' ||\n role === 'spinbutton' ||\n role === 'switch' ||\n role === 'textbox'\n ) {\n return true;\n }\n\n return isFocusable(el);\n }\n\n protected render() {\n return html`\n <div\n id=\"root\"\n part=\"root\"\n ${keyNavigation(this._onNavigate)}\n data-interaction-mode=\"keyboard\"\n role=\"toolbar\"\n aria-orientation=${this.orientation}\n aria-label=${this.label}\n >\n <div id=\"slot-wrap\" @focusin=${this._handleItemFocus}>\n <slot id=\"items\" @slotchange=${this._onSlotChange}></slot>\n </div>\n </div>\n `;\n }\n}\n\nexport default RCToolbar;\n"],"names":["toolbarStyles","css","_RCToolbar","RovingTabIndexMixin","LitElement","isFocusable","target","action","slot","el","role","html","keyNavigation","RCToolbar","__decorateClass","property","query"],"mappings":";;;AAEO,MAAMA,IAAgBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;AC2BtB,MAAMC,IAAN,MAAMA,UAAkBC,EAAoBC,CAAU,EAAE;AAAA,EAAxD,cAAA;AAAA,UAAA,GAAA,SAAA,GAKL,KAAA,QAAQ,WAIR,KAAA,cAAyC,cAKzC,KAAiB,oBAAoB,IAAI,iBAAiB,MAAM,KAAK,cAAc;AAAA,EAAA;AAAA,EAE1E,oBAA0B;AACjC,UAAM,kBAAA,GACN,KAAK,kBAAkB,QAAQ,MAAM,EAAE,iBAAiB,CAAC,UAAU,GAAG,SAAS,IAAM;AAAA,EACvF;AAAA,EAES,uBAA6B;AACpC,UAAM,qBAAA,GACN,KAAK,kBAAkB,WAAA;AAAA,EACzB;AAAA,EAEQ,eAAqB;AAC3B,IAAI,CAAC,KAAK,gBAAgBC,EAAY,KAAK,YAAY,MACvD,KAAK,eAAe,QACpB,KAAK,WAAA;AAAA,EACP;AAAA,EAEmB,aAAa;AAG9B,UAAM,WAAA;AAMN,UAAMC,IAAS,KAAK,gBAAgB,KAAK;AACzC,mBAAe,MAAM;AACnB,MAAI,KAAK,QAAQ,eAAe,KAAG,KAAK,UAAUA,CAAM;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EAEU,YAAYC,GAAkC;AACtD,YAAQA,GAAA;AAAA,MACN,KAAK;AACH,aAAK,UAAU,KAAK,QAAQ;AAC5B;AAAA,MACF,KAAK;AACH,aAAK,UAAU,KAAK,YAAY;AAChC;AAAA,MACF,KAAK;AACH,aAAK,UAAU,KAAK,SAAS;AAC7B;AAAA,MACF,KAAK;AACH,aAAK,UAAU,KAAK,QAAQ;AAC5B;AAAA,IAAA;AAAA,EAEN;AAAA,EAEmB,cAAcC,GAAkC;AACjE,WAAOA,EAAK,mBAAmB,OAAO,CAACC,MAAO,KAAK,eAAeA,CAAE,CAAC;AAAA,EACvE;AAAA,EAEQ,eAAeA,GAAsB;AAC3C,QACEA,aAAc,qBACdA,aAAc,oBACdA,aAAc,qBACdA,aAAc;AAEd,aAAO;AAGT,QAAIA,aAAc,qBAAqBA,aAAc;AACnD,aAAOA,EAAG,aAAa,MAAM;AAG/B,UAAMC,IAAOD,EAAG,aAAa,MAAM;AACnC,WACEC,MAAS,YACTA,MAAS,cACTA,MAAS,UACTA,MAAS,cACTA,MAAS,WACTA,MAAS,YACTA,MAAS,gBACTA,MAAS,YACTA,MAAS,YAEF,KAGFL,EAAYI,CAAE;AAAA,EACvB;AAAA,EAEU,SAAS;AACjB,WAAOE;AAAA;AAAA;AAAA;AAAA,UAIDC,EAAc,KAAK,WAAW,CAAC;AAAA;AAAA;AAAA,2BAGd,KAAK,WAAW;AAAA,qBACtB,KAAK,KAAK;AAAA;AAAA,uCAEQ,KAAK,gBAAgB;AAAA,yCACnB,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA,EAIzD;AACF;AApHEV,EAAO,SAAS,CAACF,CAAa;AADzB,IAAMa,IAANX;AAKLY,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAJfF,EAKX,WAAA,OAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfF,EASX,WAAA,aAAA;AAGUC,EAAA;AAAA,EADTE,EAAM,SAAS,EAAI;AAAA,GAXTH,EAYD,WAAA,QAAA;"}
|