@rcarls/rc-toolbar 0.6.0 → 0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # @rcarls/rc-toolbar
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 11680b6: Expose and navigate the orientation a widget actually renders in. An
8
+ `orientation` attribute names a layout: `horizontal` runs along the inline
9
+ axis and `vertical` along the block axis, so both turn over in vertical
10
+ writing modes, the way a native `<input type="range">` does. Toolbar,
11
+ menubar, and adaptive menu now report the rendered orientation as
12
+ `aria-orientation`, and their arrow keys follow it, so a horizontal toolbar
13
+ in vertical text navigates with ArrowDown.
14
+
15
+ `keyNavigation` treats an explicit `navigationAxis` and role defaults as
16
+ layout orientations and converts them the same way; an explicit
17
+ `aria-orientation` attribute is still used as is. Add `renderedOrientation`
18
+ and a `FlowController` that keeps a host's writing mode and direction current
19
+ for rendering.
20
+
21
+ `rc-toolbar` now reflects `orientation` to its host attribute, and its
22
+ vertical layout is keyed off that attribute rather than `aria-orientation`.
23
+
24
+ ### Patch Changes
25
+
26
+ - 5c006de: Ship component CSS minified. Package builds now run the CSS in Lit `css` styles
27
+ and light-DOM structural styles through Lightning CSS, removing comments and
28
+ whitespace while keeping source maps that resolve to each template. Rendered
29
+ styles are unchanged.
30
+
31
+ `@rcarls/rc-common` adds `cssText`, an identity tag that marks a plain CSS
32
+ string for minification. `rc-chip`, `rc-disclosure`, and `rc-accordion` now
33
+ depend on `@rcarls/rc-common` for it.
34
+
35
+ - Updated dependencies [e3dfa59]
36
+ - Updated dependencies [50d5610]
37
+ - Updated dependencies [9ee769c]
38
+ - Updated dependencies [1179f24]
39
+ - Updated dependencies [595fe37]
40
+ - Updated dependencies [38cd00c]
41
+ - Updated dependencies [5c006de]
42
+ - Updated dependencies [a6553ff]
43
+ - Updated dependencies [2205478]
44
+ - Updated dependencies [4341311]
45
+ - Updated dependencies [899bb5e]
46
+ - Updated dependencies [25fcfe0]
47
+ - Updated dependencies [51f6403]
48
+ - Updated dependencies [9caca6b]
49
+ - Updated dependencies [b764a3c]
50
+ - Updated dependencies [54d9ead]
51
+ - Updated dependencies [b9175e9]
52
+ - Updated dependencies [c8b762b]
53
+ - Updated dependencies [55e1e7f]
54
+ - Updated dependencies [f1ca82d]
55
+ - Updated dependencies [b87f27b]
56
+ - Updated dependencies [32ebead]
57
+ - Updated dependencies [bfefedd]
58
+ - Updated dependencies [c130173]
59
+ - Updated dependencies [11680b6]
60
+ - Updated dependencies [223d36c]
61
+ - Updated dependencies [7b91a44]
62
+ - Updated dependencies [aa04ead]
63
+ - Updated dependencies [ac65b5b]
64
+ - Updated dependencies [afcfef8]
65
+ - Updated dependencies [11ef1ad]
66
+ - @rcarls/rc-common@0.7.0
67
+
3
68
  ## 0.6.0
4
69
 
5
70
  ### Patch Changes
@@ -110,8 +110,17 @@
110
110
  "text": "'horizontal' | 'vertical'"
111
111
  },
112
112
  "default": "'horizontal'",
113
- "description": "Toolbar orientation, for keyboard navigation.",
114
- "attribute": "orientation"
113
+ "description": "Toolbar layout along the inline (`horizontal`) or block (`vertical`) axis.",
114
+ "attribute": "orientation",
115
+ "reflects": true
116
+ },
117
+ {
118
+ "kind": "field",
119
+ "name": "_flow",
120
+ "privacy": "protected",
121
+ "readonly": true,
122
+ "default": "new FlowController(this)",
123
+ "description": "Keeps the exposed aria-orientation on the orientation actually rendered."
115
124
  },
116
125
  {
117
126
  "kind": "field",
@@ -204,7 +213,7 @@
204
213
  "fieldName": "label"
205
214
  },
206
215
  {
207
- "description": "Toolbar orientation, for keyboard navigation.",
216
+ "description": "Toolbar layout along the inline (`horizontal`) or block (`vertical`) axis.",
208
217
  "name": "orientation",
209
218
  "type": {
210
219
  "text": "'horizontal' | 'vertical'"
@@ -1,56 +1,15 @@
1
- import { css as b, LitElement as h, html as f } from "lit";
1
+ import { css as h, LitElement as b, html as f } from "lit";
2
2
  import { property as u, query as p } from "lit/decorators.js";
3
- import { RovingTabIndexMixin as m, isFocusable as d, keyNavigation as v, keyInteraction as g } from "@rcarls/rc-common";
4
- const _ = b`
5
- :host {
6
- display: inline-block;
7
- }
8
-
9
- #root {
10
- display: flex;
11
- flex-direction: row;
12
- flex-wrap: var(--rc-toolbar-flex-wrap, nowrap);
13
- gap: var(--rc-toolbar-gap-inline, var(--rc-control-gap, 0.25em));
14
- padding-inline: var(
15
- --rc-toolbar-padding-inline,
16
- calc(var(--rc-control-padding-inline, 0.5em) / 2)
17
- );
18
- padding-block: var(
19
- --rc-toolbar-padding-block,
20
- calc(var(--rc-control-padding-block, 0.25em) / 2)
21
- );
22
- border-radius: var(--rc-toolbar-radius, var(--rc-control-radius, 0));
23
- font-family: var(--rc-font-family, inherit);
24
- font-size: var(--rc-font-size, inherit);
25
- line-height: var(--rc-line-height, normal);
26
-
27
- &[aria-orientation='vertical'] {
28
- flex-direction: column;
29
- border-radius: var(
30
- --rc-toolbar-vertical-radius,
31
- var(--rc-toolbar-radius, var(--rc-control-radius, 0))
32
- );
33
- }
34
-
35
- /* because :has(:focus-visible) doesn't work across slot boundary */
36
- &[data-interaction-mode='keyboard']:focus-within {
37
- outline: var(--rc-focus-ring, auto);
38
- outline-offset: var(--rc-focus-ring-offset, 0);
39
- }
40
- }
41
-
42
- #slot-wrap {
43
- display: contents;
44
- }
45
- `;
46
- var y = Object.defineProperty, a = (c, t, e, o) => {
3
+ import { RovingTabIndexMixin as m, FlowController as v, isFocusable as d, keyNavigation as g, keyInteraction as _, renderedOrientation as y } from "@rcarls/rc-common";
4
+ const I = h`:host{display:inline-block}#root{flex-direction:row;flex-wrap:var(--rc-toolbar-flex-wrap,nowrap);gap:var(--rc-toolbar-gap-inline,var(--rc-control-gap,.25em));padding-inline:var(--rc-toolbar-padding-inline,calc(var(--rc-control-padding-inline,.5em) / 2));padding-block:var(--rc-toolbar-padding-block,calc(var(--rc-control-padding-block,.25em) / 2));border-radius:var(--rc-toolbar-radius,var(--rc-control-radius,0));font-family:var(--rc-font-family,inherit);font-size:var(--rc-font-size,inherit);line-height:var(--rc-line-height,normal);display:flex;:host([orientation=vertical]) &{border-radius:var(--rc-toolbar-vertical-radius,var(--rc-toolbar-radius,var(--rc-control-radius,0)));flex-direction:column}&[data-interaction-mode=keyboard]:focus-within{outline:var(--rc-focus-ring,auto);outline-offset:var(--rc-focus-ring-offset,0)}}#slot-wrap{display:contents}`;
5
+ var k = Object.defineProperty, a = (c, t, e, o) => {
47
6
  for (var r = void 0, s = c.length - 1, l; s >= 0; s--)
48
7
  (l = c[s]) && (r = l(t, e, r) || r);
49
- return r && y(t, e, r), r;
8
+ return r && k(t, e, r), r;
50
9
  };
51
- const n = class n extends m(h) {
10
+ const n = class n extends m(b) {
52
11
  constructor() {
53
- super(...arguments), this.label = "Toolbar", this.orientation = "horizontal", this._disabledObserver = new MutationObserver(() => this._syncTabStop());
12
+ super(...arguments), this.label = "Toolbar", this.orientation = "horizontal", this._flow = new v(this), this._disabledObserver = new MutationObserver(() => this._syncTabStop());
54
13
  }
55
14
  connectedCallback() {
56
15
  super.connectedCallback(), this._disabledObserver.observe(this, { attributeFilter: ["disabled"], subtree: !0 });
@@ -106,10 +65,10 @@ const n = class n extends m(h) {
106
65
  <div
107
66
  id="root"
108
67
  part="root"
109
- ${v(this._onNavigate)}
110
- ${g()}
68
+ ${g(this._onNavigate)}
69
+ ${_()}
111
70
  role="toolbar"
112
- aria-orientation=${this.orientation}
71
+ aria-orientation=${y(this.orientation, this._flow.flow)}
113
72
  aria-label=${this.label}
114
73
  >
115
74
  <div id="slot-wrap" @focusin=${this._handleItemFocus}>
@@ -119,13 +78,13 @@ const n = class n extends m(h) {
119
78
  `;
120
79
  }
121
80
  };
122
- n.styles = [_];
81
+ n.styles = [I];
123
82
  let i = n;
124
83
  a([
125
84
  u({ type: String })
126
85
  ], i.prototype, "label");
127
86
  a([
128
- u({ type: String })
87
+ u({ type: String, reflect: !0 })
129
88
  ], i.prototype, "orientation");
130
89
  a([
131
90
  p("#root", !0)
@@ -133,4 +92,4 @@ a([
133
92
  export {
134
93
  i as R
135
94
  };
136
- //# sourceMappingURL=rc-toolbar-Bzh9yptT.js.map
95
+ //# sourceMappingURL=rc-toolbar-CIRFuRyL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-toolbar-CIRFuRyL.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 flex-wrap: var(--rc-toolbar-flex-wrap, nowrap);\n gap: var(--rc-toolbar-gap-inline, var(--rc-control-gap, 0.25em));\n padding-inline: var(\n --rc-toolbar-padding-inline,\n calc(var(--rc-control-padding-inline, 0.5em) / 2)\n );\n padding-block: var(\n --rc-toolbar-padding-block,\n calc(var(--rc-control-padding-block, 0.25em) / 2)\n );\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 /*\n * Layout keys off the author's orientation, not aria-orientation: the\n * exposed value reports the rendered orientation, which turns over in\n * vertical writing modes while the layout axis does not.\n */\n :host([orientation='vertical']) & {\n flex-direction: column;\n border-radius: var(\n --rc-toolbar-vertical-radius,\n var(--rc-toolbar-radius, var(--rc-control-radius, 0))\n );\n }\n\n /* because :has(:focus-visible) doesn'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 FlowController,\n isFocusable,\n keyInteraction,\n keyNavigation,\n type KeyboardNavigationAction,\n renderedOrientation,\n RovingTabIndexMixin,\n} from '@rcarls/rc-common';\n\nimport toolbarStyles from './rc-toolbar.styles.js';\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 controls, `rc-button`, or `rc-chip` elements\n * to display in the toolbar. Direct native controls and the native buttons\n * inside supported wrappers are navigable.\n * @attr label - Accessible label for this toolbar. Default label is 'Toolbar'.\n * @attr orientation - Toolbar layout: `horizontal` lays items along the inline axis,\n * `vertical` along the block axis. Both turn over in vertical writing modes, and\n * `aria-orientation` and the arrow keys follow the orientation actually rendered.\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-flex-wrap=nowrap] - Whether toolbar items wrap onto multiple lines\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 layout along the inline (`horizontal`) or block (`vertical`) axis. */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /** Keeps the exposed aria-orientation on the orientation actually rendered. */\n protected readonly _flow = new FlowController(this);\n\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n protected 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 protected _syncTabStop(): void {\n if (!this._lastFocused || isFocusable(this._lastFocused)) {\n return;\n }\n\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\n queueMicrotask(() => {\n if (this.matches(':focus-within')) {\n this.focusItem($target);\n }\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().flatMap(($element) => {\n if ($element.matches('rc-button, rc-chip')) {\n const $button = $element.querySelector(':scope > button');\n\n return $button ? [$button] : [];\n }\n\n return this._isToolbarItem($element) ? [$element] : [];\n });\n }\n\n protected _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\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=${renderedOrientation(this.orientation, this._flow.flow)}\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","FlowController","isFocusable","$target","action","$slot","$element","$button","$el","role","html","keyNavigation","keyInteraction","renderedOrientation","RCToolbar","__decorateClass","property","query"],"mappings":";;;AAEO,MAAMA,IAAgBC;;;;;;ACyCtB,MAAMC,IAAN,MAAMA,UAAkBC,EAAoBC,CAAU,EAAE;AAAA,EAAxD,cAAA;AAAA,UAAA,GAAA,SAAA,GAKL,KAAA,QAAQ,WAIR,KAAA,cAAyC,cAGzC,KAAmB,QAAQ,IAAIC,EAAe,IAAI,GAKlD,KAAmB,oBAAoB,IAAI,iBAAiB,MAAM,KAAK,cAAc;AAAA,EAAA;AAAA,EAE5E,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,EAEU,eAAqB;AAC7B,IAAI,CAAC,KAAK,gBAAgBC,EAAY,KAAK,YAAY,MAIvD,KAAK,eAAe,QACpB,KAAK,WAAA;AAAA,EACP;AAAA,EAEmB,aAAa;AAG9B,UAAM,WAAA;AAMN,UAAMC,IAAU,KAAK,gBAAgB,KAAK;AAE1C,mBAAe,MAAM;AACnB,MAAI,KAAK,QAAQ,eAAe,KAC9B,KAAK,UAAUA,CAAO;AAAA,IAE1B,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,GAAmC;AAClE,WAAOA,EAAM,iBAAA,EAAmB,QAAQ,CAACC,MAAa;AACpD,UAAIA,EAAS,QAAQ,oBAAoB,GAAG;AAC1C,cAAMC,IAAUD,EAAS,cAAc,iBAAiB;AAExD,eAAOC,IAAU,CAACA,CAAO,IAAI,CAAA;AAAA,MAC/B;AAEA,aAAO,KAAK,eAAeD,CAAQ,IAAI,CAACA,CAAQ,IAAI,CAAA;AAAA,IACtD,CAAC;AAAA,EACH;AAAA,EAEU,eAAeE,GAAuB;AAC9C,QACEA,aAAe,qBACfA,aAAe,oBACfA,aAAe,qBACfA,aAAe;AAEf,aAAO;AAGT,QAAIA,aAAe,qBAAqBA,aAAe;AACrD,aAAOA,EAAI,aAAa,MAAM;AAGhC,UAAMC,IAAOD,EAAI,aAAa,MAAM;AAEpC,WACEC,MAAS,YACTA,MAAS,cACTA,MAAS,UACTA,MAAS,cACTA,MAAS,WACTA,MAAS,YACTA,MAAS,gBACTA,MAAS,YACTA,MAAS,YAEF,KAGFP,EAAYM,CAAG;AAAA,EACxB;AAAA,EAEU,SAAS;AACjB,WAAOE;AAAA;AAAA;AAAA;AAAA,UAIDC,EAAc,KAAK,WAAW,CAAC;AAAA,UAC/BC,GAAgB;AAAA;AAAA,2BAECC,EAAoB,KAAK,aAAa,KAAK,MAAM,IAAI,CAAC;AAAA,qBAC5D,KAAK,KAAK;AAAA;AAAA,uCAEQ,KAAK,gBAAgB;AAAA,yCACnB,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA,EAIzD;AACF;AAtIEf,EAAO,SAAS,CAACF,CAAa;AADzB,IAAMkB,IAANhB;AAKLiB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAJfF,EAKX,WAAA,OAAA;AAIAC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAR9BF,EASX,WAAA,aAAA;AAMUC,EAAA;AAAA,EADTE,EAAM,SAAS,EAAI;AAAA,GAdTH,EAeD,WAAA,QAAA;"}
@@ -1,4 +1,4 @@
1
- import { R as o } from "./rc-toolbar-Bzh9yptT.js";
1
+ import { R as o } from "./rc-toolbar-CIRFuRyL.js";
2
2
  customElements.get("rc-toolbar") || customElements.define("rc-toolbar", o);
3
3
  export {
4
4
  o as RCToolbar
@@ -1,4 +1,4 @@
1
- import { R as a } from "./rc-toolbar-Bzh9yptT.js";
1
+ import { R as a } from "./rc-toolbar-CIRFuRyL.js";
2
2
  export {
3
3
  a as RCToolbar
4
4
  };
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- import { KeyboardNavigationAction } from '@rcarls/rc-common';
2
+ import { FlowController, KeyboardNavigationAction } from '@rcarls/rc-common';
3
3
  declare global {
4
4
  interface HTMLElementTagNameMap {
5
5
  'rc-toolbar': RCToolbar;
@@ -17,7 +17,9 @@ declare const RCToolbar_base: typeof LitElement & (new (...args: any[]) => impor
17
17
  * to display in the toolbar. Direct native controls and the native buttons
18
18
  * inside supported wrappers are navigable.
19
19
  * @attr label - Accessible label for this toolbar. Default label is 'Toolbar'.
20
- * @attr orientation - Toolbar orientation, for keyboard navigation.
20
+ * @attr orientation - Toolbar layout: `horizontal` lays items along the inline axis,
21
+ * `vertical` along the block axis. Both turn over in vertical writing modes, and
22
+ * `aria-orientation` and the arrow keys follow the orientation actually rendered.
21
23
  * @cssprop [--rc-toolbar-gap-inline=0.25em] - Gap between toolbar items
22
24
  * @cssprop [--rc-toolbar-padding-inline=calc(var(--rc-control-padding-inline) / 2)] - Horizontal padding on the toolbar container
23
25
  * @cssprop [--rc-toolbar-padding-block=calc(var(--rc-control-padding-block) / 2)] - Vertical padding on the toolbar container
@@ -30,8 +32,10 @@ export declare class RCToolbar extends RCToolbar_base {
30
32
  static styles: import('lit').CSSResult[];
31
33
  /** Accessible label for this toolbar. Default label is 'Toolbar'. */
32
34
  label: string;
33
- /** Toolbar orientation, for keyboard navigation. */
35
+ /** Toolbar layout along the inline (`horizontal`) or block (`vertical`) axis. */
34
36
  orientation: 'horizontal' | 'vertical';
37
+ /** Keeps the exposed aria-orientation on the orientation actually rendered. */
38
+ protected readonly _flow: FlowController;
35
39
  protected _$root: HTMLDivElement;
36
40
  protected readonly _disabledObserver: MutationObserver;
37
41
  connectedCallback(): void;
@@ -41,6 +45,6 @@ export declare class RCToolbar extends RCToolbar_base {
41
45
  protected _onNavigate(action: KeyboardNavigationAction): void;
42
46
  protected _collectItems($slot: HTMLSlotElement): Element[];
43
47
  protected _isToolbarItem($el: Element): boolean;
44
- protected render(): import('lit').TemplateResult<1>;
48
+ protected render(): import('lit-html').TemplateResult<1>;
45
49
  }
46
50
  export default RCToolbar;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.6.0",
6
+ "version": "0.7.0",
7
7
  "description": "Toolbar that groups consumer-supplied controls into one tab stop with arrow-key navigation.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  "test:browser:firefox": "vitest --run --project=firefox"
46
46
  },
47
47
  "dependencies": {
48
- "@rcarls/rc-common": "0.6.0"
48
+ "@rcarls/rc-common": "0.7.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@custom-elements-manifest/analyzer": "0.11.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-toolbar-Bzh9yptT.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 flex-wrap: var(--rc-toolbar-flex-wrap, nowrap);\n gap: var(--rc-toolbar-gap-inline, var(--rc-control-gap, 0.25em));\n padding-inline: var(\n --rc-toolbar-padding-inline,\n calc(var(--rc-control-padding-inline, 0.5em) / 2)\n );\n padding-block: var(\n --rc-toolbar-padding-block,\n calc(var(--rc-control-padding-block, 0.25em) / 2)\n );\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(\n --rc-toolbar-vertical-radius,\n var(--rc-toolbar-radius, var(--rc-control-radius, 0))\n );\n }\n\n /* because :has(:focus-visible) doesn'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.js';\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 controls, `rc-button`, or `rc-chip` elements\n * to display in the toolbar. Direct native controls and the native buttons\n * inside supported wrappers are navigable.\n * @attr label - Accessible label for this toolbar. Default label is 'Toolbar'.\n * @attr orientation - Toolbar orientation, for keyboard navigation.\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-flex-wrap=nowrap] - Whether toolbar items wrap onto multiple lines\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 protected 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 protected _syncTabStop(): void {\n if (!this._lastFocused || isFocusable(this._lastFocused)) {\n return;\n }\n\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\n queueMicrotask(() => {\n if (this.matches(':focus-within')) {\n this.focusItem($target);\n }\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().flatMap(($element) => {\n if ($element.matches('rc-button, rc-chip')) {\n const $button = $element.querySelector(':scope > button');\n\n return $button ? [$button] : [];\n }\n\n return this._isToolbarItem($element) ? [$element] : [];\n });\n }\n\n protected _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\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","$element","$button","$el","role","html","keyNavigation","keyInteraction","RCToolbar","__decorateClass","property","query"],"mappings":"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"}