@datalayer/primer-addons 1.0.21 → 1.0.22

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.
Files changed (83) hide show
  1. package/README.md +14 -0
  2. package/lib/components/appearance/AppearanceMenuWithStore.d.ts +26 -0
  3. package/lib/components/appearance/AppearanceMenuWithStore.js +21 -0
  4. package/lib/components/appearance/CollaboratorPalette.d.ts +65 -0
  5. package/lib/components/appearance/CollaboratorPalette.js +160 -0
  6. package/lib/components/appearance/index.d.ts +2 -0
  7. package/lib/components/appearance/index.js +2 -0
  8. package/lib/components/box/Box.d.ts +17 -5
  9. package/lib/components/box/Box.js +3 -5
  10. package/lib/components/calendar-picker/CalendarPicker.d.ts +35 -0
  11. package/lib/components/calendar-picker/CalendarPicker.js +146 -0
  12. package/lib/components/calendar-picker/index.d.ts +1 -0
  13. package/lib/components/calendar-picker/index.js +5 -0
  14. package/lib/components/card/Card.d.ts +6 -1
  15. package/lib/components/card/Card.js +1 -1
  16. package/lib/components/color/ColorSwatch.d.ts +1 -1
  17. package/lib/components/color-picker/ColorPicker.d.ts +97 -0
  18. package/lib/components/color-picker/ColorPicker.js +358 -0
  19. package/lib/components/color-picker/index.d.ts +1 -0
  20. package/lib/components/color-picker/index.js +5 -0
  21. package/lib/components/content-loader/ContentLoader.d.ts +1 -1
  22. package/lib/components/content-loader/ContentLoader.stories.d.ts +1 -1
  23. package/lib/components/date-picker/DatePicker.d.ts +46 -0
  24. package/lib/components/date-picker/DatePicker.js +98 -0
  25. package/lib/components/date-picker/index.d.ts +1 -0
  26. package/lib/components/date-picker/index.js +5 -0
  27. package/lib/components/icons/CircleIcon.d.ts +1 -1
  28. package/lib/components/icons/CircleIcon.stories.d.ts +1 -1
  29. package/lib/components/index.d.ts +5 -0
  30. package/lib/components/index.js +5 -0
  31. package/lib/components/logo/DatalayerText.d.ts +1 -1
  32. package/lib/components/logo/index.d.ts +0 -1
  33. package/lib/components/logo/index.js +0 -1
  34. package/lib/components/side-overlay/SideOverlay.d.ts +5 -5
  35. package/lib/components/side-overlay/SideOverlay.stories.d.ts +1 -1
  36. package/lib/components/slider/Slider.d.ts +1 -1
  37. package/lib/components/slider/Slider.stories.d.ts +1 -1
  38. package/lib/components/sliding-panel/SlidingPanel.d.ts +1 -1
  39. package/lib/components/sliding-panel/SlidingPanel.stories.d.ts +1 -1
  40. package/lib/components/toolbar/Toolbar.d.ts +2 -2
  41. package/lib/components/toolbar/Toolbar.js +0 -0
  42. package/lib/components/toolbar/ToolbarButton.d.ts +3 -1
  43. package/lib/components/toolbar/ToolbarButton.js +54 -22
  44. package/lib/components/toolbar/ToolbarDivider.d.ts +1 -1
  45. package/lib/components/toolbar/ToolbarDropdown.d.ts +3 -3
  46. package/lib/components/toolbar/ToolbarDropdown.js +66 -35
  47. package/lib/components/toolbar/ToolbarRenderer.d.ts +20 -3
  48. package/lib/components/toolbar/ToolbarRenderer.js +16 -16
  49. package/lib/components/toolbar/types.d.ts +8 -8
  50. package/lib/reactor/AppearancePlugin.d.ts +31 -0
  51. package/lib/reactor/AppearancePlugin.js +63 -0
  52. package/lib/reactor/ThemePlugin.d.ts +5 -0
  53. package/lib/reactor/ThemePlugin.js +98 -0
  54. package/lib/reactor/index.d.ts +30 -0
  55. package/lib/reactor/index.js +34 -0
  56. package/lib/reactor/page-layout/PageLayout.d.ts +148 -0
  57. package/lib/reactor/page-layout/PageLayout.js +310 -0
  58. package/lib/reactor/page-layout/PageLayoutPlugin.d.ts +59 -0
  59. package/lib/reactor/page-layout/PageLayoutPlugin.js +105 -0
  60. package/lib/reactor/page-layout/PagePanelToggle.d.ts +21 -0
  61. package/lib/reactor/page-layout/PagePanelToggle.js +29 -0
  62. package/lib/reactor/page-layout/SlotPageLayout.d.ts +36 -0
  63. package/lib/reactor/page-layout/SlotPageLayout.js +25 -0
  64. package/lib/reactor/page-layout/panelState.d.ts +28 -0
  65. package/lib/reactor/page-layout/panelState.js +49 -0
  66. package/lib/story-helpers.d.ts +2 -2
  67. package/lib/theme/DatalayerBrandThemeProvider.d.ts +1 -1
  68. package/lib/theme/DatalayerThemeProvider.d.ts +5 -5
  69. package/lib/theme/DatalayerThemeProvider.js +119 -58
  70. package/lib/theme/css/createThemeCSSVars.d.ts +1 -0
  71. package/lib/theme/css/createThemeCSSVars.js +9 -0
  72. package/lib/theme/fontStacks.d.ts +2 -0
  73. package/lib/theme/fontStacks.js +6 -0
  74. package/lib/theme/index.d.ts +2 -0
  75. package/lib/theme/index.js +2 -0
  76. package/lib/theme/palettes/ColorPalette.d.ts +3 -3
  77. package/lib/theme/portableTheme.d.ts +32 -0
  78. package/lib/theme/portableTheme.js +45 -0
  79. package/lib/utils/Helper.d.ts +2 -2
  80. package/lib/utils/Styles.d.ts +1 -1
  81. package/package.json +15 -14
  82. package/lib/components/logo/DI.d.ts +0 -19
  83. package/lib/components/logo/DI.js +0 -20
@@ -1,13 +1,18 @@
1
1
  export * from "./appearance/AppearanceControls";
2
2
  export * from "./appearance/AppearanceControlsWithStore";
3
3
  export * from "./appearance/AppearanceMenu";
4
+ export * from "./appearance/AppearanceMenuWithStore";
5
+ export * from "./appearance/CollaboratorPalette";
4
6
  export * from "./appearance/ColorModeCircle";
5
7
  export * from "./appearance/ThemePreviewCard";
6
8
  export * from "./appearance/ThemeCircle";
7
9
  export * from "./box/Box";
10
+ export * from "./calendar-picker";
8
11
  export * from "./card/Card";
9
12
  export * from "./color";
13
+ export * from "./color-picker";
10
14
  export * from "./content-loader/ContentLoader";
15
+ export * from "./date-picker";
11
16
  export * from "./closeable-flash/CloseableFlash";
12
17
  export * from "./icons/CircleIcon";
13
18
  export * from "./side-overlay/SideOverlay";
@@ -1,13 +1,18 @@
1
1
  export * from "./appearance/AppearanceControls";
2
2
  export * from "./appearance/AppearanceControlsWithStore";
3
3
  export * from "./appearance/AppearanceMenu";
4
+ export * from "./appearance/AppearanceMenuWithStore";
5
+ export * from "./appearance/CollaboratorPalette";
4
6
  export * from "./appearance/ColorModeCircle";
5
7
  export * from "./appearance/ThemePreviewCard";
6
8
  export * from "./appearance/ThemeCircle";
7
9
  export * from "./box/Box";
10
+ export * from "./calendar-picker";
8
11
  export * from "./card/Card";
9
12
  export * from "./color";
13
+ export * from "./color-picker";
10
14
  export * from "./content-loader/ContentLoader";
15
+ export * from "./date-picker";
11
16
  export * from "./closeable-flash/CloseableFlash";
12
17
  export * from "./icons/CircleIcon";
13
18
  export * from "./side-overlay/SideOverlay";
@@ -18,5 +18,5 @@ export interface DatalayerTextProps extends Omit<SVGProps<SVGGElement>, 'ref'> {
18
18
  * - "DATA" = secondaryColor (gray in the original)
19
19
  * - "LAYER" = primaryColor (green accent in the original)
20
20
  */
21
- export declare const DatalayerText: ({ primaryColor, secondaryColor, sizeMultiplier, x, y, ...groupProps }: DatalayerTextProps) => JSX.Element;
21
+ export declare const DatalayerText: ({ primaryColor, secondaryColor, sizeMultiplier, x, y, ...groupProps }: DatalayerTextProps) => React.JSX.Element;
22
22
  export default DatalayerText;
@@ -1,4 +1,3 @@
1
- export * from "./DI";
2
1
  export * from "./DatalayerLogo";
3
2
  export * from "./DatalayerLogoText";
4
3
  export * from "./DatalayerText";
@@ -1,4 +1,3 @@
1
- export * from "./DI";
2
1
  export * from "./DatalayerLogo";
3
2
  export * from "./DatalayerLogoText";
4
3
  export * from "./DatalayerText";
@@ -1,13 +1,13 @@
1
1
  export interface SideOverlayProps {
2
- closeButtonRef?: React.RefObject<HTMLButtonElement>;
3
- content: JSX.Element;
2
+ closeButtonRef?: React.RefObject<HTMLButtonElement | null>;
3
+ content: React.JSX.Element;
4
4
  direction?: 'left' | 'right';
5
- headingRef?: React.RefObject<HTMLHeadingElement>;
5
+ headingRef?: React.RefObject<HTMLElement | null>;
6
6
  isOpen?: boolean;
7
- openButtonRef?: React.RefObject<HTMLButtonElement>;
7
+ openButtonRef?: React.RefObject<HTMLButtonElement | null>;
8
8
  setIsOpen?: React.Dispatch<React.SetStateAction<boolean>>;
9
9
  width?: number | string;
10
10
  zIndex?: number;
11
11
  }
12
- export declare const SideOverlay: ({ width, direction, zIndex, ...rest }: SideOverlayProps) => import("react/jsx-runtime").JSX.Element;
12
+ export declare const SideOverlay: ({ width, direction, zIndex, ...rest }: SideOverlayProps) => import("react").JSX.Element;
13
13
  export default SideOverlay;
@@ -2,7 +2,7 @@ import type { StoryObj } from '@storybook/react';
2
2
  import { SideOverlayProps } from '../..';
3
3
  declare const meta: {
4
4
  title: string;
5
- component: ({ width, direction, zIndex, ...rest }: SideOverlayProps) => import("react/jsx-runtime").JSX.Element;
5
+ component: ({ width, direction, zIndex, ...rest }: SideOverlayProps) => import("react").JSX.Element;
6
6
  tags: string[];
7
7
  parameters: {
8
8
  layout: string;
@@ -19,5 +19,5 @@ type ConditionalProps = {
19
19
  step?: number;
20
20
  };
21
21
  export type SliderProps = CommonProps & ConditionalProps;
22
- export declare const Slider: ({ name, id, min, max, value, label, step, markers, displayValue, disabled, orientation, width, onChange, }: SliderProps) => import("react/jsx-runtime").JSX.Element;
22
+ export declare const Slider: ({ name, id, min, max, value, label, step, markers, displayValue, disabled, orientation, width, onChange, }: SliderProps) => import("react").JSX.Element;
23
23
  export default Slider;
@@ -2,7 +2,7 @@ import type { StoryObj } from '@storybook/react';
2
2
  import { SliderProps } from '../../index';
3
3
  declare const meta: {
4
4
  title: string;
5
- component: ({ name, id, min, max, value, label, step, markers, displayValue, disabled, orientation, width, onChange, }: SliderProps) => import("react/jsx-runtime").JSX.Element;
5
+ component: ({ name, id, min, max, value, label, step, markers, displayValue, disabled, orientation, width, onChange, }: SliderProps) => import("react").JSX.Element;
6
6
  tags: string[];
7
7
  parameters: {
8
8
  layout: string;
@@ -15,5 +15,5 @@ export interface SlidingPanelProps {
15
15
  panelSize?: number | string;
16
16
  fullWidth?: boolean;
17
17
  }
18
- export declare const SlidingPanel: ({ isOpen, message, details, onDismiss, position, variant, durationMs, transitionMs, zIndex, offset, panelSize, fullWidth, }: SlidingPanelProps) => import("react/jsx-runtime").JSX.Element | null;
18
+ export declare const SlidingPanel: ({ isOpen, message, details, onDismiss, position, variant, durationMs, transitionMs, zIndex, offset, panelSize, fullWidth, }: SlidingPanelProps) => import("react").JSX.Element | null;
19
19
  export default SlidingPanel;
@@ -2,7 +2,7 @@ import type { StoryObj } from '@storybook/react';
2
2
  import { type SlidingPanelProps } from './SlidingPanel';
3
3
  declare const meta: {
4
4
  title: string;
5
- component: ({ isOpen, message, details, onDismiss, position, variant, durationMs, transitionMs, zIndex, offset, panelSize, fullWidth, }: SlidingPanelProps) => import("react/jsx-runtime").JSX.Element | null;
5
+ component: ({ isOpen, message, details, onDismiss, position, variant, durationMs, transitionMs, zIndex, offset, panelSize, fullWidth, }: SlidingPanelProps) => import("react").JSX.Element | null;
6
6
  tags: string[];
7
7
  parameters: {
8
8
  layout: string;
@@ -1,3 +1,3 @@
1
- import type { ToolbarProps } from './types';
2
- export declare function Toolbar({ items, extraItems, className, disabled, ariaLabel, overflow, }: ToolbarProps): import("react/jsx-runtime").JSX.Element;
1
+ import type { ToolbarProps } from "./types";
2
+ export declare function Toolbar({ items, extraItems, className, disabled, ariaLabel, overflow, }: ToolbarProps): import("react").JSX.Element;
3
3
  export default Toolbar;
Binary file
@@ -3,6 +3,8 @@ export interface ToolbarButtonProps {
3
3
  item: ToolbarButtonItem;
4
4
  /** Size variant: 'small' for floating toolbar, 'medium' for fixed toolbar */
5
5
  size?: 'small' | 'medium';
6
+ /** Print `ariaLabel` beside the icon — see the module doc. Off by default. */
7
+ showLabel?: boolean;
6
8
  }
7
- export declare function ToolbarButton({ item, size }: ToolbarButtonProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function ToolbarButton({ item, size, showLabel, }: ToolbarButtonProps): import("react").JSX.Element;
8
10
  export default ToolbarButton;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /*
3
3
  * Copyright (c) 2025-2026 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
@@ -15,11 +15,21 @@ import { jsx as _jsx } from "react/jsx-runtime";
15
15
  * and the tooltip of a disabled action is precisely where the why-disabled
16
16
  * explanation lives.
17
17
  *
18
+ * `showLabel` prints that same name beside the icon instead of leaving it in
19
+ * the tooltip alone. On the toolbar's own line an icon earns its keep — Bold,
20
+ * Italic, Underline read at a glance, and a name beside each would crowd a
21
+ * strip already short on room. Inside the "..." overflow menu there is a
22
+ * whole row to spend and nothing to read at a glance until the pointer
23
+ * happens to rest on one: a tooltip nobody is hovering says nothing, the way
24
+ * `ariaLabel` says it whether or not anyone points at the row at all. The
25
+ * `Toolbar` sets it on that menu alone; a host wiring `ToolbarButton` up on
26
+ * its own line does not need to know the flag exists.
27
+ *
18
28
  * @module components/toolbar/ToolbarButton
19
29
  */
20
- import { isValidElement } from 'react';
30
+ import { isValidElement, useState } from 'react';
21
31
  import { Tooltip } from '@primer/react';
22
- export function ToolbarButton({ item, size = 'medium' }) {
32
+ export function ToolbarButton({ item, size = 'medium', showLabel = false, }) {
23
33
  const { ariaLabel, title, icon, label, isActive, onClick, disabled } = item;
24
34
  // Resolve icon → React element.
25
35
  // Octicon components use React.forwardRef, which returns an *object*
@@ -41,34 +51,56 @@ export function ToolbarButton({ item, size = 'medium' }) {
41
51
  iconElement = _jsx("span", { style: { fontSize: 12, fontWeight: 600, lineHeight: 1 }, children: label });
42
52
  }
43
53
  const btnSize = size === 'small' ? 28 : 32;
44
- const button = (_jsx("button", { type: "button", "aria-label": ariaLabel, "aria-disabled": disabled || undefined, onMouseDown: (e) => e.preventDefault(), onClick: disabled ? undefined : onClick, style: {
54
+ // Only when there is a name to show, and only where it was asked for:
55
+ // showLabel with no ariaLabel (should never happen — it is required on
56
+ // the item — but this keeps a bare icon rather than an empty gap) falls
57
+ // back to the icon-only layout below.
58
+ const printLabel = showLabel && Boolean(ariaLabel);
59
+ /*
60
+ * Hover, as state rather than as a style written onto the element.
61
+ *
62
+ * The `Tooltip` around a titled button replays its `onMouseEnter` from a
63
+ * timeout, by which time React has cleared the event's `currentTarget`:
64
+ * writing `e.currentTarget.style` there threw "Cannot read properties of
65
+ * null (reading 'style')". A ref would not do either — the Tooltip clones
66
+ * the button with a ref of its own.
67
+ */
68
+ const [hovered, setHovered] = useState(false);
69
+ const lit = hovered && !disabled;
70
+ const button = (_jsxs("button", { type: "button", "aria-label": ariaLabel, "aria-disabled": disabled || undefined, onMouseDown: (e) => e.preventDefault(), onClick: disabled ? undefined : onClick, style: {
45
71
  display: 'inline-flex',
46
72
  alignItems: 'center',
47
- justifyContent: 'center',
48
- width: btnSize,
73
+ justifyContent: printLabel ? 'flex-start' : 'center',
74
+ gap: printLabel ? 6 : 0,
75
+ // No explicit `width` when labelled: sized to its own icon-plus-name
76
+ // content, the same as `ToolbarDropdown`'s trigger — the two sit in
77
+ // the same overflow menu, and a button stretched to fill it beside a
78
+ // dropdown sized to its own text would read as two different kinds
79
+ // of row rather than one consistent list.
80
+ width: printLabel ? undefined : btnSize,
81
+ minWidth: btnSize,
49
82
  height: btnSize,
50
- padding: 0,
83
+ padding: printLabel ? '0 8px' : 0,
51
84
  margin: 0,
52
85
  border: 'none',
53
86
  borderRadius: 6,
54
87
  cursor: disabled ? 'not-allowed' : 'pointer',
55
- background: isActive ? 'var(--bgColor-accent-muted, rgba(9,105,218,0.1))' : 'transparent',
56
- color: isActive ? 'var(--fgColor-accent, #0969da)' : 'var(--fgColor-muted, #656d76)',
88
+ background: lit
89
+ ? 'var(--bgColor-neutral-muted, rgba(175,184,193,0.2))'
90
+ : isActive
91
+ ? 'var(--bgColor-accent-muted, rgba(9,105,218,0.1))'
92
+ : 'transparent',
93
+ color: lit
94
+ ? 'var(--fgColor-default, #1f2328)'
95
+ : isActive
96
+ ? 'var(--fgColor-accent, #0969da)'
97
+ : 'var(--fgColor-muted, #656d76)',
57
98
  opacity: disabled ? 0.5 : 1,
58
99
  lineHeight: 1,
59
- }, onMouseEnter: (e) => {
60
- if (!disabled) {
61
- e.currentTarget.style.background = 'var(--bgColor-neutral-muted, rgba(175,184,193,0.2))';
62
- e.currentTarget.style.color = 'var(--fgColor-default, #1f2328)';
63
- }
64
- }, onMouseLeave: (e) => {
65
- e.currentTarget.style.background = isActive
66
- ? 'var(--bgColor-accent-muted, rgba(9,105,218,0.1))'
67
- : 'transparent';
68
- e.currentTarget.style.color = isActive
69
- ? 'var(--fgColor-accent, #0969da)'
70
- : 'var(--fgColor-muted, #656d76)';
71
- }, children: iconElement }));
100
+ fontSize: size === 'small' ? 12 : 14,
101
+ fontFamily: 'inherit',
102
+ whiteSpace: 'nowrap',
103
+ }, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: [iconElement, printLabel && _jsx("span", { children: ariaLabel })] }));
72
104
  // No title: nothing to say, no wrapper to say it with.
73
105
  return title ? (_jsx(Tooltip, { text: title, direction: "s", children: button })) : (button);
74
106
  }
@@ -2,5 +2,5 @@ export interface ToolbarDividerProps {
2
2
  /** Orientation: vertical for horizontal toolbars, horizontal for vertical */
3
3
  orientation?: 'vertical' | 'horizontal';
4
4
  }
5
- export declare function ToolbarDivider({ orientation }: ToolbarDividerProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function ToolbarDivider({ orientation }: ToolbarDividerProps): import("react").JSX.Element;
6
6
  export default ToolbarDivider;
@@ -1,8 +1,8 @@
1
- import type { ToolbarDropdownItem } from './types';
1
+ import type { ToolbarDropdownItem } from "./types";
2
2
  export interface ToolbarDropdownProps {
3
3
  item: ToolbarDropdownItem;
4
4
  /** Size variant */
5
- size?: 'small' | 'medium';
5
+ size?: "small" | "medium";
6
6
  }
7
- export declare function ToolbarDropdown({ item, size }: ToolbarDropdownProps): import("react/jsx-runtime").JSX.Element;
7
+ export declare function ToolbarDropdown({ item, size, }: ToolbarDropdownProps): import("react").JSX.Element;
8
8
  export default ToolbarDropdown;
@@ -16,9 +16,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  *
17
17
  * @module components/toolbar/ToolbarDropdown
18
18
  */
19
- import { isValidElement, useMemo } from 'react';
20
- import { ActionMenu, ActionList, Text } from '@primer/react';
21
- import { Box } from '../box/Box';
19
+ import { isValidElement, useMemo, useState } from "react";
20
+ import { ActionMenu, ActionList, Text } from "@primer/react";
21
+ import { Box } from "../box/Box";
22
22
  /**
23
23
  * Resolve an icon prop to a ReactNode.
24
24
  *
@@ -38,55 +38,86 @@ function renderIcon(icon) {
38
38
  }
39
39
  /** Whether any dropdown option in the list has an icon. */
40
40
  function hasAnyIcon(options) {
41
- return options.some(o => !!o.icon);
41
+ return options.some((o) => !!o.icon);
42
42
  }
43
- export function ToolbarDropdown({ item, size = 'medium' }) {
43
+ export function ToolbarDropdown({ item, size = "medium", }) {
44
44
  const { ariaLabel, icon, label, minWidth, options, disabled } = item;
45
- // Highlight the trigger when any option is active.
46
- const anyActive = useMemo(() => options.some(o => o.isActive), [options]);
45
+ const [open, setOpen] = useState(false);
46
+ /*
47
+ * When the trigger is highlighted.
48
+ *
49
+ * Not simply "an option is active". A dropdown that *selects* something —
50
+ * the cell type, say — always has exactly one active option, so that rule
51
+ * painted it in the accent colour permanently: a control that looked
52
+ * switched on before it had been touched, in a blue that was Primer's
53
+ * rather than the theme's whenever the accent variable did not reach it.
54
+ *
55
+ * A labelled dropdown already shows its current value in the label, so the
56
+ * highlight tells the reader nothing they cannot see. Only a label-less one
57
+ * — an icon that means "filter on" — has a state worth colouring, and any
58
+ * dropdown is worth marking while its menu is open.
59
+ */
60
+ const anyActive = useMemo(() => !label && options.some((o) => o.isActive), [label, options]);
47
61
  // If any option has an icon we reserve a leading-visual column for all rows.
48
62
  const showLeadingVisual = useMemo(() => hasAnyIcon(options), [options]);
49
- const btnSize = size === 'small' ? 28 : 32;
50
- return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsxs("button", { type: "button", "aria-label": ariaLabel, title: ariaLabel, disabled: disabled, style: {
51
- display: 'inline-flex',
52
- alignItems: 'center',
53
- justifyContent: 'center',
63
+ const btnSize = size === "small" ? 28 : 32;
64
+ return (_jsxs(ActionMenu, { open: open, onOpenChange: setOpen, children: [_jsx(ActionMenu.Anchor, { children: _jsxs("button", { type: "button", "aria-label": ariaLabel, title: ariaLabel, disabled: disabled, style: {
65
+ display: "inline-flex",
66
+ alignItems: "center",
67
+ justifyContent: "center",
54
68
  gap: 4,
55
69
  minWidth: btnSize,
56
70
  height: btnSize,
57
- padding: label ? '0 8px' : 0,
71
+ padding: label ? "0 8px" : 0,
58
72
  margin: 0,
59
- border: 'none',
73
+ border: "none",
60
74
  borderRadius: 6,
61
- cursor: disabled ? 'not-allowed' : 'pointer',
62
- background: anyActive
63
- ? 'var(--bgColor-accent-muted, rgba(9,105,218,0.1))'
64
- : 'transparent',
65
- color: anyActive
66
- ? 'var(--fgColor-accent, #0969da)'
67
- : 'var(--fgColor-muted, #656d76)',
75
+ cursor: disabled ? "not-allowed" : "pointer",
76
+ /*
77
+ Neutral while the menu is open, not accented.
78
+
79
+ An accent here is a colour the host has to have defined for this
80
+ subtree, and where it has not the browser falls back to Primer's
81
+ blue — so the control turned blue the moment it was clicked, in a
82
+ hue belonging to no theme on the page. The neutral pair is the
83
+ same one the hover state uses, which the theme does define.
84
+ */
85
+ background: anyActive || open
86
+ ? "var(--bgColor-neutral-muted, rgba(175,184,193,0.2))"
87
+ : "transparent",
88
+ color: anyActive || open
89
+ ? "var(--fgColor-default, #1f2328)"
90
+ : "var(--fgColor-muted, #656d76)",
68
91
  opacity: disabled ? 0.5 : 1,
69
- fontSize: size === 'small' ? 12 : 14,
70
- fontWeight: 'normal',
71
- fontFamily: 'inherit',
92
+ fontSize: size === "small" ? 12 : 14,
93
+ fontWeight: "normal",
94
+ fontFamily: "inherit",
72
95
  lineHeight: 1,
73
96
  }, onMouseEnter: (e) => {
74
97
  if (!disabled) {
75
98
  e.currentTarget.style.background =
76
- 'var(--bgColor-neutral-muted, rgba(175,184,193,0.2))';
77
- e.currentTarget.style.color = 'var(--fgColor-default, #1f2328)';
99
+ "var(--bgColor-neutral-muted, rgba(175,184,193,0.2))";
100
+ e.currentTarget.style.color = "var(--fgColor-default, #1f2328)";
78
101
  }
79
102
  }, onMouseLeave: (e) => {
80
- e.currentTarget.style.background = anyActive
81
- ? 'var(--bgColor-accent-muted, rgba(9,105,218,0.1))'
82
- : 'transparent';
83
- e.currentTarget.style.color = anyActive
84
- ? 'var(--fgColor-accent, #0969da)'
85
- : 'var(--fgColor-muted, #656d76)';
103
+ e.currentTarget.style.background =
104
+ anyActive || open
105
+ ? "var(--bgColor-neutral-muted, rgba(175,184,193,0.2))"
106
+ : "transparent";
107
+ e.currentTarget.style.color =
108
+ anyActive || open
109
+ ? "var(--fgColor-default, #1f2328)"
110
+ : "var(--fgColor-muted, #656d76)";
86
111
  }, children: [renderIcon(icon), label && (_jsx("span", { style: {
87
- display: 'inline-block',
112
+ display: "inline-block",
88
113
  minWidth: minWidth ? minWidth : undefined,
89
- textAlign: 'left',
90
- }, children: label }))] }) }), _jsx(ActionMenu.Overlay, { width: "auto", children: _jsx(ActionList, { children: options.map(option => (_jsxs(ActionList.Item, { onSelect: option.onClick, disabled: option.disabled, active: option.isActive, children: [showLeadingVisual && (_jsx(ActionList.LeadingVisual, { children: option.icon ? renderIcon(option.icon) : _jsx(Box, { sx: { width: 16 } }) })), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', gap: 3 }, children: [_jsx(Text, { children: option.label }), option.shortcut && (_jsx(Text, { sx: { color: 'fg.subtle', fontSize: 0, fontFamily: 'mono' }, children: option.shortcut }))] })] }, option.key))) }) })] }));
114
+ textAlign: "left",
115
+ }, children: label }))] }) }), _jsx(ActionMenu.Overlay, { width: "auto", children: _jsx(ActionList, { children: options.map((option) => (_jsxs(ActionList.Item, { onSelect: option.onClick, disabled: option.disabled, active: option.isActive, children: [showLeadingVisual && (_jsx(ActionList.LeadingVisual, { children: option.icon ? (renderIcon(option.icon)) : (_jsx(Box, { sx: { width: 16 } })) })), _jsxs(Box, { sx: {
116
+ display: "flex",
117
+ justifyContent: "space-between",
118
+ alignItems: "center",
119
+ width: "100%",
120
+ gap: 3,
121
+ }, children: [_jsx(Text, { children: option.label }), option.shortcut && (_jsx(Text, { sx: { color: "fg.subtle", fontSize: 0, fontFamily: "mono" }, children: option.shortcut }))] })] }, option.key))) }) })] }));
91
122
  }
92
123
  export default ToolbarDropdown;
@@ -1,11 +1,28 @@
1
- import type { ToolbarItem } from './types';
1
+ import type { ToolbarItem } from "./types";
2
2
  export interface ToolbarRendererProps {
3
3
  items: ToolbarItem[];
4
4
  disabled?: boolean;
5
- size?: 'small' | 'medium';
5
+ size?: "small" | "medium";
6
+ /**
7
+ * Print a button's name beside its icon instead of leaving it in the
8
+ * tooltip alone — see `ToolbarButton`. Meaningless for a dropdown, which
9
+ * already shows its own label wherever it is drawn.
10
+ */
11
+ showLabel?: boolean;
12
+ /**
13
+ * How the caller lays the items out: along a row (a toolbar line, the
14
+ * default) or down a column (the "..." overflow menu).
15
+ *
16
+ * Only dividers read it. A divider is drawn across the direction of travel
17
+ * — a vertical bar between items on a row, a horizontal rule between groups
18
+ * in a column. Left vertical in a column it became a 20px-tall empty row
19
+ * with a 1px line down its left edge, which is exactly what showed under
20
+ * the last item of every group in the overflow menu.
21
+ */
22
+ direction?: "row" | "column";
6
23
  }
7
24
  /**
8
25
  * Sort items by order, then render each one according to its type.
9
26
  */
10
- export declare function ToolbarRenderer({ items, disabled, size }: ToolbarRendererProps): import("react/jsx-runtime").JSX.Element;
27
+ export declare function ToolbarRenderer({ items, disabled, size, showLabel, direction, }: ToolbarRendererProps): import("react").JSX.Element;
11
28
  export default ToolbarRenderer;
@@ -10,30 +10,30 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
10
10
  *
11
11
  * @module components/toolbar/ToolbarRenderer
12
12
  */
13
- import { Fragment } from 'react';
14
- import { Box } from '../box/Box';
15
- import { ToolbarButton } from './ToolbarButton';
16
- import { ToolbarDropdown } from './ToolbarDropdown';
17
- import { ToolbarDivider } from './ToolbarDivider';
13
+ import { Fragment } from "react";
14
+ import { Box } from "../box/Box";
15
+ import { ToolbarButton } from "./ToolbarButton";
16
+ import { ToolbarDropdown } from "./ToolbarDropdown";
17
+ import { ToolbarDivider } from "./ToolbarDivider";
18
18
  /**
19
19
  * Sort items by order, then render each one according to its type.
20
20
  */
21
- export function ToolbarRenderer({ items, disabled, size = 'medium' }) {
21
+ export function ToolbarRenderer({ items, disabled, size = "medium", showLabel = false, direction = "row", }) {
22
22
  const sorted = [...items]
23
- .filter(item => !item.hidden)
23
+ .filter((item) => !item.hidden)
24
24
  .sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
25
- return (_jsx(_Fragment, { children: sorted.map(item => {
25
+ return (_jsx(_Fragment, { children: sorted.map((item) => {
26
26
  const itemDisabled = disabled || item.disabled;
27
27
  switch (item.type) {
28
- case 'button':
29
- return (_jsx(Fragment, { children: _jsx(ToolbarButton, { item: { ...item, disabled: itemDisabled }, size: size }) }, item.key));
30
- case 'dropdown':
28
+ case "button":
29
+ return (_jsx(Fragment, { children: _jsx(ToolbarButton, { item: { ...item, disabled: itemDisabled }, size: size, showLabel: showLabel }) }, item.key));
30
+ case "dropdown":
31
31
  return (_jsx(Fragment, { children: _jsx(ToolbarDropdown, { item: { ...item, disabled: itemDisabled }, size: size }) }, item.key));
32
- case 'divider':
33
- return (_jsx(Fragment, { children: _jsx(ToolbarDivider, {}) }, item.key));
34
- case 'spacer':
35
- return (_jsx(Box, { sx: { flex: '1 1 auto', minWidth: 8 } }, item.key));
36
- case 'custom':
32
+ case "divider":
33
+ return (_jsx(Fragment, { children: _jsx(ToolbarDivider, { orientation: direction === "column" ? "horizontal" : "vertical" }) }, item.key));
34
+ case "spacer":
35
+ return (_jsx(Box, { sx: { flex: "1 1 auto", minWidth: 8 } }, item.key));
36
+ case "custom":
37
37
  return _jsx(Fragment, { children: item.render() }, item.key);
38
38
  default:
39
39
  return null;
@@ -1,9 +1,9 @@
1
- import type { ReactNode } from 'react';
2
- import type { IconProps } from '@primer/octicons-react';
1
+ import type { ReactNode } from "react";
2
+ import type { IconProps } from "@primer/octicons-react";
3
3
  /**
4
4
  * Toolbar item types that can be registered in a toolbar.
5
5
  */
6
- export type ToolbarItemType = 'button' | 'dropdown' | 'divider' | 'spacer' | 'custom';
6
+ export type ToolbarItemType = "button" | "dropdown" | "divider" | "spacer" | "custom";
7
7
  /**
8
8
  * Base toolbar item definition.
9
9
  */
@@ -25,7 +25,7 @@ export interface ToolbarItemBase {
25
25
  * Toolbar button item definition.
26
26
  */
27
27
  export interface ToolbarButtonItem extends ToolbarItemBase {
28
- type: 'button';
28
+ type: "button";
29
29
  /** Accessible label */
30
30
  ariaLabel: string;
31
31
  /** Tooltip text */
@@ -64,7 +64,7 @@ export interface ToolbarDropdownOption {
64
64
  * Toolbar dropdown item definition.
65
65
  */
66
66
  export interface ToolbarDropdownItem extends ToolbarItemBase {
67
- type: 'dropdown';
67
+ type: "dropdown";
68
68
  /** Accessible label */
69
69
  ariaLabel: string;
70
70
  /** Tooltip text */
@@ -86,7 +86,7 @@ export interface ToolbarDropdownItem extends ToolbarItemBase {
86
86
  * Toolbar divider item definition.
87
87
  */
88
88
  export interface ToolbarDividerItem extends ToolbarItemBase {
89
- type: 'divider';
89
+ type: "divider";
90
90
  }
91
91
  /**
92
92
  * Toolbar spacer item definition.
@@ -95,13 +95,13 @@ export interface ToolbarDividerItem extends ToolbarItemBase {
95
95
  * the trailing edge — e.g. a status indicator kept away from the actions.
96
96
  */
97
97
  export interface ToolbarSpacerItem extends ToolbarItemBase {
98
- type: 'spacer';
98
+ type: "spacer";
99
99
  }
100
100
  /**
101
101
  * Toolbar custom item definition.
102
102
  */
103
103
  export interface ToolbarCustomItem extends ToolbarItemBase {
104
- type: 'custom';
104
+ type: "custom";
105
105
  /** Custom render function */
106
106
  render: () => ReactNode;
107
107
  }
@@ -0,0 +1,31 @@
1
+ import type { ReactorReactOutput } from "@datalayer/reactor/react";
2
+ export declare const APPEARANCE_PLUGIN_NAME = "@datalayer/primer-appearance";
3
+ /** The id of the slot component, for a host that looks it up. */
4
+ export declare const APPEARANCE_MENU_COMPONENT_ID = "appearance-menu";
5
+ export type AppearancePluginConfig = {
6
+ /** The slot the menu renders into. */
7
+ slot: string;
8
+ /**
9
+ * Its place among that slot's components: lower first. High by default, so
10
+ * the menu sits at the trailing edge of a header, after a view selector.
11
+ */
12
+ order: number;
13
+ /** The trigger's size in pixels. */
14
+ size: number;
15
+ /** The trigger's shape. */
16
+ shape: "square" | "circle";
17
+ /** Which way the overlay opens from the trigger. */
18
+ placement: "bottom-start" | "bottom-end";
19
+ /**
20
+ * Whether the overlay carries the chosen theme's description and its
21
+ * preview, or only the circles.
22
+ */
23
+ showThemePreviews: boolean;
24
+ /**
25
+ * Whether choosing a theme also switches to its default color mode. Off,
26
+ * as in the public header: a person who chose dark keeps dark.
27
+ */
28
+ applyThemeColorMode: boolean;
29
+ };
30
+ export declare const AppearancePlugin: import("@datalayer/reactor").ReactorPlugin<AppearancePluginConfig, unknown, ReactorReactOutput>;
31
+ export default AppearancePlugin;