@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.
- package/README.md +14 -0
- package/lib/components/appearance/AppearanceMenuWithStore.d.ts +26 -0
- package/lib/components/appearance/AppearanceMenuWithStore.js +21 -0
- package/lib/components/appearance/CollaboratorPalette.d.ts +65 -0
- package/lib/components/appearance/CollaboratorPalette.js +160 -0
- package/lib/components/appearance/index.d.ts +2 -0
- package/lib/components/appearance/index.js +2 -0
- package/lib/components/box/Box.d.ts +17 -5
- package/lib/components/box/Box.js +3 -5
- package/lib/components/calendar-picker/CalendarPicker.d.ts +35 -0
- package/lib/components/calendar-picker/CalendarPicker.js +146 -0
- package/lib/components/calendar-picker/index.d.ts +1 -0
- package/lib/components/calendar-picker/index.js +5 -0
- package/lib/components/card/Card.d.ts +6 -1
- package/lib/components/card/Card.js +1 -1
- package/lib/components/color/ColorSwatch.d.ts +1 -1
- package/lib/components/color-picker/ColorPicker.d.ts +97 -0
- package/lib/components/color-picker/ColorPicker.js +358 -0
- package/lib/components/color-picker/index.d.ts +1 -0
- package/lib/components/color-picker/index.js +5 -0
- package/lib/components/content-loader/ContentLoader.d.ts +1 -1
- package/lib/components/content-loader/ContentLoader.stories.d.ts +1 -1
- package/lib/components/date-picker/DatePicker.d.ts +46 -0
- package/lib/components/date-picker/DatePicker.js +98 -0
- package/lib/components/date-picker/index.d.ts +1 -0
- package/lib/components/date-picker/index.js +5 -0
- package/lib/components/icons/CircleIcon.d.ts +1 -1
- package/lib/components/icons/CircleIcon.stories.d.ts +1 -1
- package/lib/components/index.d.ts +5 -0
- package/lib/components/index.js +5 -0
- package/lib/components/logo/DatalayerText.d.ts +1 -1
- package/lib/components/logo/index.d.ts +0 -1
- package/lib/components/logo/index.js +0 -1
- package/lib/components/side-overlay/SideOverlay.d.ts +5 -5
- package/lib/components/side-overlay/SideOverlay.stories.d.ts +1 -1
- package/lib/components/slider/Slider.d.ts +1 -1
- package/lib/components/slider/Slider.stories.d.ts +1 -1
- package/lib/components/sliding-panel/SlidingPanel.d.ts +1 -1
- package/lib/components/sliding-panel/SlidingPanel.stories.d.ts +1 -1
- package/lib/components/toolbar/Toolbar.d.ts +2 -2
- package/lib/components/toolbar/Toolbar.js +0 -0
- package/lib/components/toolbar/ToolbarButton.d.ts +3 -1
- package/lib/components/toolbar/ToolbarButton.js +54 -22
- package/lib/components/toolbar/ToolbarDivider.d.ts +1 -1
- package/lib/components/toolbar/ToolbarDropdown.d.ts +3 -3
- package/lib/components/toolbar/ToolbarDropdown.js +66 -35
- package/lib/components/toolbar/ToolbarRenderer.d.ts +20 -3
- package/lib/components/toolbar/ToolbarRenderer.js +16 -16
- package/lib/components/toolbar/types.d.ts +8 -8
- package/lib/reactor/AppearancePlugin.d.ts +31 -0
- package/lib/reactor/AppearancePlugin.js +63 -0
- package/lib/reactor/ThemePlugin.d.ts +5 -0
- package/lib/reactor/ThemePlugin.js +98 -0
- package/lib/reactor/index.d.ts +30 -0
- package/lib/reactor/index.js +34 -0
- package/lib/reactor/page-layout/PageLayout.d.ts +148 -0
- package/lib/reactor/page-layout/PageLayout.js +310 -0
- package/lib/reactor/page-layout/PageLayoutPlugin.d.ts +59 -0
- package/lib/reactor/page-layout/PageLayoutPlugin.js +105 -0
- package/lib/reactor/page-layout/PagePanelToggle.d.ts +21 -0
- package/lib/reactor/page-layout/PagePanelToggle.js +29 -0
- package/lib/reactor/page-layout/SlotPageLayout.d.ts +36 -0
- package/lib/reactor/page-layout/SlotPageLayout.js +25 -0
- package/lib/reactor/page-layout/panelState.d.ts +28 -0
- package/lib/reactor/page-layout/panelState.js +49 -0
- package/lib/story-helpers.d.ts +2 -2
- package/lib/theme/DatalayerBrandThemeProvider.d.ts +1 -1
- package/lib/theme/DatalayerThemeProvider.d.ts +5 -5
- package/lib/theme/DatalayerThemeProvider.js +119 -58
- package/lib/theme/css/createThemeCSSVars.d.ts +1 -0
- package/lib/theme/css/createThemeCSSVars.js +9 -0
- package/lib/theme/fontStacks.d.ts +2 -0
- package/lib/theme/fontStacks.js +6 -0
- package/lib/theme/index.d.ts +2 -0
- package/lib/theme/index.js +2 -0
- package/lib/theme/palettes/ColorPalette.d.ts +3 -3
- package/lib/theme/portableTheme.d.ts +32 -0
- package/lib/theme/portableTheme.js +45 -0
- package/lib/utils/Helper.d.ts +2 -2
- package/lib/utils/Styles.d.ts +1 -1
- package/package.json +15 -14
- package/lib/components/logo/DI.d.ts +0 -19
- 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";
|
package/lib/components/index.js
CHANGED
|
@@ -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,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<
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2
|
-
export declare function Toolbar({ items, extraItems, className, disabled, ariaLabel, overflow, }: ToolbarProps): import("react
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
56
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
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
|
|
1
|
+
import type { ToolbarDropdownItem } from "./types";
|
|
2
2
|
export interface ToolbarDropdownProps {
|
|
3
3
|
item: ToolbarDropdownItem;
|
|
4
4
|
/** Size variant */
|
|
5
|
-
size?:
|
|
5
|
+
size?: "small" | "medium";
|
|
6
6
|
}
|
|
7
|
-
export declare function ToolbarDropdown({ item, size }: ToolbarDropdownProps): import("react
|
|
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
|
|
20
|
-
import { ActionMenu, ActionList, Text } from
|
|
21
|
-
import { Box } from
|
|
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 =
|
|
43
|
+
export function ToolbarDropdown({ item, size = "medium", }) {
|
|
44
44
|
const { ariaLabel, icon, label, minWidth, options, disabled } = item;
|
|
45
|
-
|
|
46
|
-
|
|
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 ===
|
|
50
|
-
return (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsxs("button", { type: "button", "aria-label": ariaLabel, title: ariaLabel, disabled: disabled, style: {
|
|
51
|
-
display:
|
|
52
|
-
alignItems:
|
|
53
|
-
justifyContent:
|
|
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 ?
|
|
71
|
+
padding: label ? "0 8px" : 0,
|
|
58
72
|
margin: 0,
|
|
59
|
-
border:
|
|
73
|
+
border: "none",
|
|
60
74
|
borderRadius: 6,
|
|
61
|
-
cursor: disabled ?
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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 ===
|
|
70
|
-
fontWeight:
|
|
71
|
-
fontFamily:
|
|
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
|
-
|
|
77
|
-
e.currentTarget.style.color =
|
|
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 =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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:
|
|
112
|
+
display: "inline-block",
|
|
88
113
|
minWidth: minWidth ? minWidth : undefined,
|
|
89
|
-
textAlign:
|
|
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: {
|
|
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
|
|
1
|
+
import type { ToolbarItem } from "./types";
|
|
2
2
|
export interface ToolbarRendererProps {
|
|
3
3
|
items: ToolbarItem[];
|
|
4
4
|
disabled?: boolean;
|
|
5
|
-
size?:
|
|
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
|
|
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
|
|
14
|
-
import { Box } from
|
|
15
|
-
import { ToolbarButton } from
|
|
16
|
-
import { ToolbarDropdown } from
|
|
17
|
-
import { ToolbarDivider } from
|
|
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 =
|
|
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
|
|
29
|
-
return (_jsx(Fragment, { children: _jsx(ToolbarButton, { item: { ...item, disabled: itemDisabled }, size: size }) }, item.key));
|
|
30
|
-
case
|
|
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
|
|
33
|
-
return (_jsx(Fragment, { children: _jsx(ToolbarDivider, {}) }, item.key));
|
|
34
|
-
case
|
|
35
|
-
return (_jsx(Box, { sx: { flex:
|
|
36
|
-
case
|
|
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
|
|
2
|
-
import type { IconProps } from
|
|
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 =
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
98
|
+
type: "spacer";
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* Toolbar custom item definition.
|
|
102
102
|
*/
|
|
103
103
|
export interface ToolbarCustomItem extends ToolbarItemBase {
|
|
104
|
-
type:
|
|
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;
|