@scalewing/react 1.18.0 → 1.19.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,11 @@
1
1
  # @scalewing/react
2
2
 
3
+ ## 1.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 596b74b: `Tooltip` `disabled` (`docs/requests/teisoro-tooltip-disabled.md`, Teisoro's workspace navigation). `disabled?: boolean` turns the tooltip off, not its trigger, which stays mounted, enabled and focusable: the tooltip element is not rendered, the trigger keeps only its own `aria-describedby`, and Escape reaches the page. Focus, hover and touch are still followed, so a trigger that still has focus, the pointer or an open touch toggle shows the tooltip as soon as it is enabled again. `disabled` must match between the server render and the first client render. A product toggles it at a breakpoint instead of rendering the trigger with and without a `Tooltip`, which mounted a new trigger and lost its focus. Without `disabled` the markup and behavior are unchanged. No new classes, tokens or dependencies.
8
+
3
9
  ## 1.18.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -247,7 +247,7 @@ An option's optional `description` (a `ReactNode`) is secondary text for that op
247
247
 
248
248
  `Progress` shows a known value between zero and a positive maximum. It uses native progressbar semantics and displays the value and maximum beside the localized label. Invalid bounds throw instead of silently clamping. Optional `tone` is `accent`, `success`, or `danger`. `showCount={false}` hides the visible `value / max` count when the page shows its own count caption, so the count appears once; the progress bar still exposes its value and maximum.
249
249
 
250
- `Tooltip` adds supplementary plain-text help to one labelled, focusable trigger. Supply localized `content` and an existing trigger element with its own accessible name. It opens on hover or focus, closes on pointer leave, blur, Escape, or outside touch, and toggles on touch. Keep required instructions visible outside the tooltip.
250
+ `Tooltip` adds supplementary plain-text help to one labelled, focusable trigger. Supply localized `content` and an existing trigger element with its own accessible name. It opens on hover or focus, closes on pointer leave, blur, Escape, or outside touch, and toggles on touch. Keep required instructions visible outside the tooltip. `disabled` turns the tooltip off, not its trigger: the trigger stays mounted, enabled and focusable, and there is no tooltip, no `aria-describedby` from it, and Escape is left to the page. Use it when what the tooltip says is visible at some widths, such as text shown only from `md` up, instead of rendering the trigger with and without a `Tooltip`, which mounts a new trigger and drops its focus. Focus, hover and touch are still followed, so a trigger that still has focus, the pointer or an open touch toggle shows the tooltip as soon as it is enabled again (Escape pressed while disabled reaches the page and does not stop that). `disabled` must be the same in the server render and the first client render, or hydration mismatches; read a breakpoint through a hydration-safe store, such as `useSyncExternalStore` with a server snapshot.
251
251
 
252
252
  `Separator` divides sections with a token-colored line. It is horizontal by default; use `orientation="vertical"` in a flex row. Set `decorative` when the line only supports layout so assistive technology ignores it.
253
253
 
@@ -1,8 +1,18 @@
1
1
  import { type ReactElement } from 'react';
2
2
  export type TooltipProps = {
3
3
  content: string;
4
+ /**
5
+ * Turns the tooltip off, not its trigger: no tooltip, no description and no
6
+ * Escape handling, while the trigger stays mounted, enabled and focusable
7
+ * (and keeps its focus). Focus, hover and touch are still followed, so the
8
+ * tooltip shows as soon as it is enabled again on a trigger that still has
9
+ * focus, the pointer or an open touch toggle; Escape pressed while disabled
10
+ * reaches the page and does not stop that. It must match between the server
11
+ * render and the first client render.
12
+ */
13
+ disabled?: boolean;
4
14
  trigger: ReactElement<{
5
15
  'aria-describedby'?: string;
6
16
  }>;
7
17
  };
8
- export declare function Tooltip({ content, trigger }: TooltipProps): import("react").JSX.Element;
18
+ export declare function Tooltip({ content, disabled, trigger }: TooltipProps): import("react").JSX.Element;
@@ -1,15 +1,18 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { cloneElement, useEffect, useId, useRef, useState, } from 'react';
4
- export function Tooltip({ content, trigger }) {
4
+ export function Tooltip({ content, disabled = false, trigger }) {
5
5
  if (!content.trim())
6
6
  throw new RangeError('content must not be empty');
7
+ // `open` follows focus, hover and touch even while disabled; `shown` is
8
+ // what the page gets.
7
9
  const [open, setOpen] = useState(false);
10
+ const shown = open && !disabled;
8
11
  const id = useId();
9
12
  const wrapperRef = useRef(null);
10
- const describedBy = [trigger.props['aria-describedby'], id]
13
+ const describedBy = [trigger.props['aria-describedby'], disabled ? undefined : id]
11
14
  .filter(Boolean)
12
- .join(' ');
15
+ .join(' ') || undefined;
13
16
  useEffect(() => {
14
17
  if (!open)
15
18
  return;
@@ -27,7 +30,7 @@ export function Tooltip({ content, trigger }) {
27
30
  }, onFocusCapture: () => setOpen(true), onKeyDownCapture: (event) => {
28
31
  // Escape hides a visible tooltip and nothing else, so a surrounding
29
32
  // Dialog does not also close. A hidden tooltip leaves Escape alone.
30
- if (event.key !== 'Escape' || !open)
33
+ if (event.key !== 'Escape' || !shown)
31
34
  return;
32
35
  event.preventDefault();
33
36
  setOpen(false);
@@ -40,5 +43,5 @@ export function Tooltip({ content, trigger }) {
40
43
  }, onPointerDownCapture: (event) => {
41
44
  if (event.pointerType === 'touch')
42
45
  setOpen((current) => !current);
43
- }, ref: wrapperRef, children: [cloneElement(trigger, { 'aria-describedby': describedBy }), _jsx("span", { className: "sw-tooltip", hidden: !open, id: id, role: "tooltip", children: content })] }));
46
+ }, ref: wrapperRef, children: [cloneElement(trigger, { 'aria-describedby': describedBy }), disabled ? null : (_jsx("span", { className: "sw-tooltip", hidden: !shown, id: id, role: "tooltip", children: content }))] }));
44
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalewing/react",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "Scalewing DOM components and package-owned CSS utilities.",
5
5
  "type": "module",
6
6
  "license": "MIT",