@cratis/components 4.20.0 → 4.21.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/compat-manifest.json +11 -11
- package/dist/esm/Chat/ChatConversation.d.ts +8 -1
- package/dist/esm/Chat/ChatConversation.d.ts.map +1 -1
- package/dist/esm/Chat/ChatConversation.js +2 -2
- package/dist/esm/Chat/ChatConversation.js.map +1 -1
- package/dist/esm/Chat/ChatSidebar.d.ts +9 -2
- package/dist/esm/Chat/ChatSidebar.d.ts.map +1 -1
- package/dist/esm/Chat/ChatSidebar.js +2 -2
- package/dist/esm/Chat/ChatSidebar.js.map +1 -1
- package/dist/esm/Common/ActionMenubar.d.ts.map +1 -1
- package/dist/esm/Common/ActionMenubar.js +11 -6
- package/dist/esm/Common/ActionMenubar.js.map +1 -1
- package/dist/esm/Common/ToolbarFocusMode.d.ts +9 -1
- package/dist/esm/Common/ToolbarFocusMode.d.ts.map +1 -1
- package/dist/esm/Common/ToolbarFocusMode.js +1 -0
- package/dist/esm/Common/ToolbarFocusMode.js.map +1 -1
- package/dist/esm/Common/ToolbarRovingContext.d.ts +39 -0
- package/dist/esm/Common/ToolbarRovingContext.d.ts.map +1 -0
- package/dist/esm/Common/ToolbarRovingContext.js +40 -0
- package/dist/esm/Common/ToolbarRovingContext.js.map +1 -0
- package/dist/esm/Common/useToolbarKeyboardNavigation.d.ts +2 -0
- package/dist/esm/Common/useToolbarKeyboardNavigation.d.ts.map +1 -1
- package/dist/esm/Common/useToolbarKeyboardNavigation.js +164 -15
- package/dist/esm/Common/useToolbarKeyboardNavigation.js.map +1 -1
- package/dist/esm/DataTables/DataTableCore.d.ts +19 -1
- package/dist/esm/DataTables/DataTableCore.d.ts.map +1 -1
- package/dist/esm/DataTables/DataTableCore.js +19 -14
- package/dist/esm/DataTables/DataTableCore.js.map +1 -1
- package/dist/esm/DataTables/DataTableRowProcessing.d.ts +11 -0
- package/dist/esm/DataTables/DataTableRowProcessing.d.ts.map +1 -0
- package/dist/esm/DataTables/DataTableRowProcessing.js +8 -0
- package/dist/esm/DataTables/DataTableRowProcessing.js.map +1 -0
- package/dist/esm/DataTables/DataTableSort.d.ts +9 -0
- package/dist/esm/DataTables/DataTableSort.d.ts.map +1 -0
- package/dist/esm/DataTables/DataTableSort.js +4 -0
- package/dist/esm/DataTables/DataTableSort.js.map +1 -0
- package/dist/esm/DataTables/DataTableSortDirection.d.ts +8 -0
- package/dist/esm/DataTables/DataTableSortDirection.d.ts.map +1 -0
- package/dist/esm/DataTables/DataTableSortDirection.js +8 -0
- package/dist/esm/DataTables/DataTableSortDirection.js.map +1 -0
- package/dist/esm/DataTables/index.d.ts +3 -0
- package/dist/esm/DataTables/index.d.ts.map +1 -1
- package/dist/esm/DataTables/index.js +2 -0
- package/dist/esm/DataTables/index.js.map +1 -1
- package/dist/esm/DataTables/useControllableState.d.ts +10 -0
- package/dist/esm/DataTables/useControllableState.d.ts.map +1 -0
- package/dist/esm/DataTables/useControllableState.js +15 -0
- package/dist/esm/DataTables/useControllableState.js.map +1 -0
- package/dist/esm/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/esm/Toolbar/Toolbar.js +3 -2
- package/dist/esm/Toolbar/Toolbar.js.map +1 -1
- package/dist/esm/Toolbar/ToolbarButton.d.ts.map +1 -1
- package/dist/esm/Toolbar/ToolbarButton.js +4 -2
- package/dist/esm/Toolbar/ToolbarButton.js.map +1 -1
- package/dist/esm/Toolbar/ToolbarFanOutItem.d.ts.map +1 -1
- package/dist/esm/Toolbar/ToolbarFanOutItem.js +10 -2
- package/dist/esm/Toolbar/ToolbarFanOutItem.js.map +1 -1
- package/dist/esm/Toolbar/ToolbarFolder.d.ts.map +1 -1
- package/dist/esm/Toolbar/ToolbarFolder.js +10 -2
- package/dist/esm/Toolbar/ToolbarFolder.js.map +1 -1
- package/package.json +5 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolbarButton.js","sources":["../../../Toolbar/ToolbarButton.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport type {\n ButtonHTMLAttributes,\n HTMLAttributes,\n} from 'react';\nimport { IconDisplay } from '../Common/Icon';\nimport type { Icon } from '../Common/Icon';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\nimport { useToolbarDragContext } from './ToolbarDragContext';\nimport { useToolbarFolderMode } from './ToolbarFolderContext';\nimport { useToolbarItemVisibility } from './ToolbarItemVisibilityContext';\n\n/** Stable part attributes for {@link ToolbarButton}. */\nexport interface ToolbarButtonParts {\n /** Native button root. */\n root?: ButtonHTMLAttributes<HTMLButtonElement>;\n /** Icon wrapper. */\n icon?: HTMLAttributes<HTMLSpanElement>;\n /** Text/title label wrapper. */\n label?: HTMLAttributes<HTMLSpanElement>;\n}\n\n/** Props for the {@link ToolbarButton} component. */\nexport interface ToolbarButtonProps {\n /** React icon node or consumer-owned icon-font class. Components installs no icon font. */\n icon?: Icon;\n\n /** Optional text-first content (for example `120%`); when non-empty it renders instead of {@link icon}. */\n text?: string;\n\n /** Title text shown when the user hovers over the button. */\n title: string;\n\n /** Whether the button is currently in the active/selected state. */\n active?: boolean;\n\n /** Callback invoked when the button is clicked. */\n onClick?: () => void;\n\n /** Position of the tooltip relative to the button (default: 'right'). */\n tooltipPosition?: TooltipPosition;\n\n /** Extra class name for the native button. */\n className?: string;\n\n /** Stable button part attributes. */\n pt?: ToolbarButtonParts;\n\n /**\n * Whether this button can be dragged onto a surface.\n * When omitted the value is inherited from the parent {@link Toolbar}'s `draggable` prop.\n */\n draggable?: boolean;\n\n /**\n * Optional data associated with this button for identification during drag & drop.\n * The value is passed to {@link onDragStart} and serialised onto the HTML5\n * `DataTransfer` object as `application/json` so drop targets can read it.\n */\n data?: unknown;\n\n /**\n * Callback invoked when a drag operation starts on this button.\n * Receives the button's {@link data} and the originating drag event.\n */\n onDragStart?: (data: unknown, event: React.DragEvent<HTMLButtonElement>) => void;\n}\n\n/**\n * An icon button with a tooltip, intended to be placed inside a {@link Toolbar}.\n * Uses the shared {@link Tooltip} component for consistent hover labels.\n */\nexport const ToolbarButton = ({\n icon,\n text,\n title,\n active,\n onClick,\n tooltipPosition = 'right',\n draggable,\n data,\n onDragStart,\n className,\n pt,\n}: ToolbarButtonProps) => {\n const dragContext = useToolbarDragContext();\n const folderMode = useToolbarFolderMode();\n const isToolbarItemVisible = useToolbarItemVisibility();\n const isListMode = folderMode === 'list';\n const isDraggable = draggable ?? dragContext.draggable;\n\n const handleDragStart = (event: React.DragEvent<HTMLButtonElement>) => {\n event.dataTransfer.setData('application/json', JSON.stringify(data ?? null));\n event.dataTransfer.effectAllowed = 'copy';\n onDragStart?.(data, event);\n dragContext.onItemDragStart?.(data, event);\n };\n\n const activeClass = active ? 'toolbar-button--active' : '';\n const draggableClass = isDraggable ? 'toolbar-button--draggable' : '';\n const hasText = typeof text === 'string' && text.length > 0;\n const resolvedIcon = icon !== undefined && icon !== null && (typeof icon !== 'string' || icon.length > 0) ? icon : null;\n\n // List mode: icon + title label rendered side by side (no floating tooltip needed).\n if (isListMode) {\n return (\n <button\n aria-pressed={active}\n {...pt?.root}\n type='button'\n aria-label={title}\n onClick={onClick}\n draggable={isDraggable}\n onDragStart={isDraggable ? handleDragStart : undefined}\n className={`toolbar-button toolbar-button--list cratis:h-10 cratis:px-3 cratis:w-full cratis:flex cratis:items-center cratis:justify-start cratis:gap-2 cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${draggableClass} ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='button'\n data-active={active || undefined}\n data-selected={active || undefined}\n >\n {resolvedIcon !== null && (\n <span\n {...pt?.icon}\n className={pt?.icon?.className}\n data-cratis-part='icon'\n >\n <IconDisplay\n icon={resolvedIcon}\n className='cratis:text-lg cratis:flex-shrink-0'\n />\n </span>\n )}\n <span\n {...pt?.label}\n className={`toolbar-button__label ${pt?.label?.className ?? ''}`}\n data-cratis-part='label'\n >\n {title}\n </span>\n </button>\n );\n }\n\n const buttonSizeClass = hasText ? 'cratis:h-10 cratis:px-3 cratis:min-w-[4rem]' : 'cratis:w-10 cratis:h-10';\n const buttonContent = hasText ? (\n <span\n {...pt?.label}\n className={`toolbar-button__text ${pt?.label?.className ?? ''}`}\n data-cratis-part='label'\n >\n {text}\n </span>\n ) : resolvedIcon === null ? null : (\n <span\n {...pt?.icon}\n className={pt?.icon?.className}\n data-cratis-part='icon'\n >\n <IconDisplay icon={resolvedIcon} className='cratis:text-lg' />\n </span>\n );\n\n return (\n <Tooltip\n content={title}\n position={tooltipPosition}\n disabled={!isToolbarItemVisible}\n >\n <button\n aria-pressed={active}\n {...pt?.root}\n type='button'\n aria-label={title}\n onClick={onClick}\n draggable={isDraggable}\n onDragStart={isDraggable ? handleDragStart : undefined}\n className={`toolbar-button ${buttonSizeClass} cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${draggableClass} ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='button'\n data-active={active || undefined}\n data-selected={active || undefined}\n >\n {buttonContent}\n </button>\n </Tooltip>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolbarButton.js","sources":["../../../Toolbar/ToolbarButton.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport type {\n ButtonHTMLAttributes,\n HTMLAttributes,\n} from 'react';\nimport { IconDisplay } from '../Common/Icon';\nimport type { Icon } from '../Common/Icon';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\nimport { useToolbarDragContext } from './ToolbarDragContext';\nimport { useToolbarFolderMode } from './ToolbarFolderContext';\nimport { useToolbarItemVisibility } from './ToolbarItemVisibilityContext';\nimport { useRovingTool } from '../Common/ToolbarRovingContext';\n\n/** Stable part attributes for {@link ToolbarButton}. */\nexport interface ToolbarButtonParts {\n /** Native button root. */\n root?: ButtonHTMLAttributes<HTMLButtonElement>;\n /** Icon wrapper. */\n icon?: HTMLAttributes<HTMLSpanElement>;\n /** Text/title label wrapper. */\n label?: HTMLAttributes<HTMLSpanElement>;\n}\n\n/** Props for the {@link ToolbarButton} component. */\nexport interface ToolbarButtonProps {\n /** React icon node or consumer-owned icon-font class. Components installs no icon font. */\n icon?: Icon;\n\n /** Optional text-first content (for example `120%`); when non-empty it renders instead of {@link icon}. */\n text?: string;\n\n /** Title text shown when the user hovers over the button. */\n title: string;\n\n /** Whether the button is currently in the active/selected state. */\n active?: boolean;\n\n /** Callback invoked when the button is clicked. */\n onClick?: () => void;\n\n /** Position of the tooltip relative to the button (default: 'right'). */\n tooltipPosition?: TooltipPosition;\n\n /** Extra class name for the native button. */\n className?: string;\n\n /** Stable button part attributes. */\n pt?: ToolbarButtonParts;\n\n /**\n * Whether this button can be dragged onto a surface.\n * When omitted the value is inherited from the parent {@link Toolbar}'s `draggable` prop.\n */\n draggable?: boolean;\n\n /**\n * Optional data associated with this button for identification during drag & drop.\n * The value is passed to {@link onDragStart} and serialised onto the HTML5\n * `DataTransfer` object as `application/json` so drop targets can read it.\n */\n data?: unknown;\n\n /**\n * Callback invoked when a drag operation starts on this button.\n * Receives the button's {@link data} and the originating drag event.\n */\n onDragStart?: (data: unknown, event: React.DragEvent<HTMLButtonElement>) => void;\n}\n\n/**\n * An icon button with a tooltip, intended to be placed inside a {@link Toolbar}.\n * Uses the shared {@link Tooltip} component for consistent hover labels.\n */\nexport const ToolbarButton = ({\n icon,\n text,\n title,\n active,\n onClick,\n tooltipPosition = 'right',\n draggable,\n data,\n onDragStart,\n className,\n pt,\n}: ToolbarButtonProps) => {\n const dragContext = useToolbarDragContext();\n const folderMode = useToolbarFolderMode();\n const isToolbarItemVisible = useToolbarItemVisibility();\n const rovingTool = useRovingTool<HTMLButtonElement>(pt?.root?.tabIndex, pt?.root?.onFocus);\n const isListMode = folderMode === 'list';\n const isDraggable = draggable ?? dragContext.draggable;\n\n const handleDragStart = (event: React.DragEvent<HTMLButtonElement>) => {\n event.dataTransfer.setData('application/json', JSON.stringify(data ?? null));\n event.dataTransfer.effectAllowed = 'copy';\n onDragStart?.(data, event);\n dragContext.onItemDragStart?.(data, event);\n };\n\n const activeClass = active ? 'toolbar-button--active' : '';\n const draggableClass = isDraggable ? 'toolbar-button--draggable' : '';\n const hasText = typeof text === 'string' && text.length > 0;\n const resolvedIcon = icon !== undefined && icon !== null && (typeof icon !== 'string' || icon.length > 0) ? icon : null;\n\n // List mode: icon + title label rendered side by side (no floating tooltip needed).\n if (isListMode) {\n return (\n <button\n aria-pressed={active}\n {...pt?.root}\n {...rovingTool}\n type='button'\n aria-label={title}\n onClick={onClick}\n draggable={isDraggable}\n onDragStart={isDraggable ? handleDragStart : undefined}\n className={`toolbar-button toolbar-button--list cratis:h-10 cratis:px-3 cratis:w-full cratis:flex cratis:items-center cratis:justify-start cratis:gap-2 cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${draggableClass} ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='button'\n data-active={active || undefined}\n data-selected={active || undefined}\n >\n {resolvedIcon !== null && (\n <span\n {...pt?.icon}\n className={pt?.icon?.className}\n data-cratis-part='icon'\n >\n <IconDisplay\n icon={resolvedIcon}\n className='cratis:text-lg cratis:flex-shrink-0'\n />\n </span>\n )}\n <span\n {...pt?.label}\n className={`toolbar-button__label ${pt?.label?.className ?? ''}`}\n data-cratis-part='label'\n >\n {title}\n </span>\n </button>\n );\n }\n\n const buttonSizeClass = hasText ? 'cratis:h-10 cratis:px-3 cratis:min-w-[4rem]' : 'cratis:w-10 cratis:h-10';\n const buttonContent = hasText ? (\n <span\n {...pt?.label}\n className={`toolbar-button__text ${pt?.label?.className ?? ''}`}\n data-cratis-part='label'\n >\n {text}\n </span>\n ) : resolvedIcon === null ? null : (\n <span\n {...pt?.icon}\n className={pt?.icon?.className}\n data-cratis-part='icon'\n >\n <IconDisplay icon={resolvedIcon} className='cratis:text-lg' />\n </span>\n );\n\n return (\n <Tooltip\n content={title}\n position={tooltipPosition}\n disabled={!isToolbarItemVisible}\n >\n <button\n aria-pressed={active}\n {...pt?.root}\n {...rovingTool}\n type='button'\n aria-label={title}\n onClick={onClick}\n draggable={isDraggable}\n onDragStart={isDraggable ? handleDragStart : undefined}\n className={`toolbar-button ${buttonSizeClass} cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${draggableClass} ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='button'\n data-active={active || undefined}\n data-selected={active || undefined}\n >\n {buttonContent}\n </button>\n </Tooltip>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolbarFanOutItem.d.ts","sourceRoot":"","sources":["../../../Toolbar/ToolbarFanOutItem.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EACV,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,SAAS,EAMjB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ToolbarFanOutItem.d.ts","sourceRoot":"","sources":["../../../Toolbar/ToolbarFanOutItem.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,EACV,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,SAAS,EAMjB,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAgB,CAAC;AAE3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAmB,CAAC;AAMzD,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IAC/B,gCAAgC;IAChC,IAAI,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IACtC,6BAA6B;IAC7B,OAAO,CAAC,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;IAClD,2BAA2B;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;CAC1C;AAED,yDAAyD;AACzD,MAAM,WAAW,sBAAsB;IACnC,yEAAyE;IACzE,IAAI,EAAE,IAAI,CAAC;IAEX,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAEhB,iFAAiF;IACjF,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC,+EAA+E;IAC/E,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;IAEnD,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,sCAAsC;IACtC,EAAE,CAAC,EAAE,kBAAkB,CAAC;IAExB,4DAA4D;IAC5D,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,kFAQ3B,sBAAsB,sBA2IxB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useRef,
|
|
2
|
+
import { useState, useRef, useCallback, useId, useEffect } from 'react';
|
|
3
|
+
import { useRovingTool } from '../Common/ToolbarRovingContext.js';
|
|
3
4
|
import { IconDisplay } from '../Common/Icon.js';
|
|
4
5
|
import { Tooltip } from '../Common/Tooltip.js';
|
|
5
6
|
import { useToolbarItemVisibility, ToolbarItemVisibilityProvider } from './ToolbarItemVisibilityContext.js';
|
|
@@ -10,6 +11,13 @@ const ToolbarFanOutItem = ({ icon, tooltip, tooltipPosition = 'right', fanOutDir
|
|
|
10
11
|
const isToolbarItemVisible = useToolbarItemVisibility();
|
|
11
12
|
const containerRef = useRef(null);
|
|
12
13
|
const triggerRef = useRef(null);
|
|
14
|
+
const rovingTrigger = useRovingTool(pt?.trigger?.tabIndex, pt?.trigger?.onFocus);
|
|
15
|
+
const rovingTriggerRef = rovingTrigger.ref;
|
|
16
|
+
const setTriggerRef = useCallback((element) => {
|
|
17
|
+
triggerRef.current = element;
|
|
18
|
+
if (typeof rovingTriggerRef === 'function')
|
|
19
|
+
rovingTriggerRef(element);
|
|
20
|
+
}, [rovingTriggerRef]);
|
|
13
21
|
const panelRef = useRef(null);
|
|
14
22
|
const generatedPanelId = useId();
|
|
15
23
|
const panelId = pt?.panel?.id ?? generatedPanelId;
|
|
@@ -68,7 +76,7 @@ const ToolbarFanOutItem = ({ icon, tooltip, tooltipPosition = 'right', fanOutDir
|
|
|
68
76
|
const panelVisibleClass = isExpanded ? 'toolbar-fanout-panel--visible' : '';
|
|
69
77
|
const panelSettledClass = isExpanded && isSettled ? 'toolbar-fanout-panel--settled' : '';
|
|
70
78
|
const directionClass = `toolbar-fanout-panel--${fanOutDirection}`;
|
|
71
|
-
return (jsxs("div", { ...pt?.root, className: `toolbar-fanout-item ${pt?.root?.className ?? ''} ${className ?? ''}`, "data-cratis-part": 'fanout-root', "data-open": isExpanded || undefined, ref: containerRef, children: [jsx(Tooltip, { content: tooltip, position: tooltipPosition, disabled: isExpanded || !isToolbarItemVisible, children: jsx("button", { ...pt?.trigger, ref:
|
|
79
|
+
return (jsxs("div", { ...pt?.root, className: `toolbar-fanout-item ${pt?.root?.className ?? ''} ${className ?? ''}`, "data-cratis-part": 'fanout-root', "data-open": isExpanded || undefined, ref: containerRef, children: [jsx(Tooltip, { content: tooltip, position: tooltipPosition, disabled: isExpanded || !isToolbarItemVisible, children: jsx("button", { ...pt?.trigger, tabIndex: rovingTrigger.tabIndex, onFocus: rovingTrigger.onFocus, ref: setTriggerRef, type: 'button', "aria-label": tooltip, "aria-expanded": isExpanded, "aria-controls": panelId, onClick: handleToggle, className: `toolbar-button cratis:w-10 cratis:h-10 cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${pt?.trigger?.className ?? ''}`, "data-cratis-part": 'fanout-trigger', "data-open": isExpanded || undefined, children: jsx(IconDisplay, { icon: icon, className: 'cratis:text-lg' }) }) }), jsx("div", { ...pt?.panel, id: panelId, role: 'group', "aria-label": tooltip, ref: panelRef, className: `toolbar-fanout-panel ${directionClass} ${panelVisibleClass} ${panelSettledClass} ${pt?.panel?.className ?? ''}`, "data-cratis-part": 'fanout-panel', "data-expanded": isExpanded || undefined, "data-open": isExpanded || undefined, "data-direction": fanOutDirection, "data-settled": isSettled || undefined, "aria-hidden": !isExpanded, inert: !isExpanded, onTransitionEnd: handleTransitionEnd, children: jsx(ToolbarItemVisibilityProvider, { value: isExpanded && isToolbarItemVisible, children: children }) })] }));
|
|
72
80
|
};
|
|
73
81
|
|
|
74
82
|
export { ToolbarFanOutItem };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolbarFanOutItem.js","sources":["../../../Toolbar/ToolbarFanOutItem.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport React, {\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { IconDisplay } from '../Common/Icon';\nimport type { Icon } from '../Common/Icon';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\nimport {\n ToolbarItemVisibilityProvider,\n useToolbarItemVisibility,\n} from './ToolbarItemVisibilityContext';\n\n/** Stable part attributes for {@link ToolbarFanOutItem}. */\nexport interface ToolbarFanOutParts {\n /** Fan-out composition root. */\n root?: HTMLAttributes<HTMLDivElement>;\n /** Native trigger button. */\n trigger?: ButtonHTMLAttributes<HTMLButtonElement>;\n /** Expanded tool panel. */\n panel?: HTMLAttributes<HTMLDivElement>;\n}\n\n/** Props for the {@link ToolbarFanOutItem} component. */\nexport interface ToolbarFanOutItemProps {\n /** React icon node or consumer-owned icon-font class for the trigger. */\n icon: Icon;\n\n /** Tooltip text shown when hovering over the trigger button. */\n tooltip: string;\n\n /** Position of the tooltip relative to the trigger button (default: 'right'). */\n tooltipPosition?: TooltipPosition;\n\n /** Direction the panel fans out from the trigger button (default: 'right'). */\n fanOutDirection?: 'right' | 'left' | 'up' | 'down';\n\n /** Extra class name for the fan-out root. */\n className?: string;\n\n /** Stable fan-out part attributes. */\n pt?: ToolbarFanOutParts;\n\n /** The toolbar items to render inside the fan-out panel. */\n children: ReactNode;\n}\n\n/**\n * A toolbar button that fans out a horizontal panel of sub-tool buttons when clicked.\n *\n * Place this inside a vertical {@link Toolbar}. When the button is clicked, a pill-shaped\n * panel slides out to the side (right by default) containing the provided children.\n * The panel animates in/out using a clip-path reveal transition.\n *\n * - Clicking the button again closes the panel\n * - Clicking anywhere outside the panel also closes it\n */\nexport const ToolbarFanOutItem = ({\n icon,\n tooltip,\n tooltipPosition = 'right',\n fanOutDirection = 'right',\n className,\n pt,\n children,\n}: ToolbarFanOutItemProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [isSettled, setIsSettled] = useState(false);\n const isToolbarItemVisible = useToolbarItemVisibility();\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const generatedPanelId = useId();\n const panelId = pt?.panel?.id ?? generatedPanelId;\n\n // A settled panel has `clip-path: none`, which cannot interpolate — closing\n // straight from it would snap the panel shut instead of wiping it closed.\n // Put an equivalent inset back and let the browser observe it (the forced\n // reflow) before React removes the visible class, so the close transition\n // has an interpolable starting value.\n const collapse = useCallback(() => {\n const panel = panelRef.current;\n if (panel && panel.classList.contains('toolbar-fanout-panel--settled')) {\n panel.style.setProperty('clip-path', 'inset(0 0 0 0 round 1rem)');\n panel.style.setProperty('transition', 'none');\n void panel.offsetWidth;\n panel.style.removeProperty('transition');\n panel.style.removeProperty('clip-path');\n }\n setIsSettled(false);\n setIsExpanded(false);\n }, []);\n\n const handleToggle = () => {\n if (isExpanded) {\n collapse();\n } else {\n setIsExpanded(true);\n }\n };\n\n const handleTransitionEnd = (event: React.TransitionEvent<HTMLDivElement>) => {\n if (\n event.target === panelRef.current &&\n event.propertyName === 'clip-path' &&\n isExpanded\n ) {\n setIsSettled(true);\n }\n };\n\n // Close the fan-out when clicking outside\n useEffect(() => {\n if (!isExpanded) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n collapse();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n collapse();\n window.setTimeout(() => triggerRef.current?.focus(), 0);\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape, true);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape, true);\n };\n }, [isExpanded, collapse]);\n\n const activeClass = isExpanded ? 'toolbar-button--active' : '';\n const panelVisibleClass = isExpanded ? 'toolbar-fanout-panel--visible' : '';\n const panelSettledClass =\n isExpanded && isSettled ? 'toolbar-fanout-panel--settled' : '';\n const directionClass = `toolbar-fanout-panel--${fanOutDirection}`;\n\n return (\n <div\n {...pt?.root}\n className={`toolbar-fanout-item ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='fanout-root'\n data-open={isExpanded || undefined}\n ref={containerRef}\n >\n <Tooltip\n content={tooltip}\n position={tooltipPosition}\n disabled={isExpanded || !isToolbarItemVisible}\n >\n <button\n {...pt?.trigger}\n ref={triggerRef}\n type='button'\n aria-label={tooltip}\n aria-expanded={isExpanded}\n aria-controls={panelId}\n onClick={handleToggle}\n className={`toolbar-button cratis:w-10 cratis:h-10 cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${pt?.trigger?.className ?? ''}`}\n data-cratis-part='fanout-trigger'\n data-open={isExpanded || undefined}\n >\n <IconDisplay icon={icon} className='cratis:text-lg' />\n </button>\n </Tooltip>\n <div\n {...pt?.panel}\n id={panelId}\n role='group'\n aria-label={tooltip}\n ref={panelRef}\n className={`toolbar-fanout-panel ${directionClass} ${panelVisibleClass} ${panelSettledClass} ${pt?.panel?.className ?? ''}`}\n data-cratis-part='fanout-panel'\n data-expanded={isExpanded || undefined}\n data-open={isExpanded || undefined}\n data-direction={fanOutDirection}\n data-settled={isSettled || undefined}\n aria-hidden={!isExpanded}\n inert={!isExpanded}\n onTransitionEnd={handleTransitionEnd}\n >\n <ToolbarItemVisibilityProvider value={isExpanded && isToolbarItemVisible}>\n {children}\n </ToolbarItemVisibilityProvider>\n </div>\n </div>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolbarFanOutItem.js","sources":["../../../Toolbar/ToolbarFanOutItem.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport React, {\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport { useRovingTool } from '../Common/ToolbarRovingContext';\nimport { IconDisplay } from '../Common/Icon';\nimport type { Icon } from '../Common/Icon';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\nimport {\n ToolbarItemVisibilityProvider,\n useToolbarItemVisibility,\n} from './ToolbarItemVisibilityContext';\n\n/** Stable part attributes for {@link ToolbarFanOutItem}. */\nexport interface ToolbarFanOutParts {\n /** Fan-out composition root. */\n root?: HTMLAttributes<HTMLDivElement>;\n /** Native trigger button. */\n trigger?: ButtonHTMLAttributes<HTMLButtonElement>;\n /** Expanded tool panel. */\n panel?: HTMLAttributes<HTMLDivElement>;\n}\n\n/** Props for the {@link ToolbarFanOutItem} component. */\nexport interface ToolbarFanOutItemProps {\n /** React icon node or consumer-owned icon-font class for the trigger. */\n icon: Icon;\n\n /** Tooltip text shown when hovering over the trigger button. */\n tooltip: string;\n\n /** Position of the tooltip relative to the trigger button (default: 'right'). */\n tooltipPosition?: TooltipPosition;\n\n /** Direction the panel fans out from the trigger button (default: 'right'). */\n fanOutDirection?: 'right' | 'left' | 'up' | 'down';\n\n /** Extra class name for the fan-out root. */\n className?: string;\n\n /** Stable fan-out part attributes. */\n pt?: ToolbarFanOutParts;\n\n /** The toolbar items to render inside the fan-out panel. */\n children: ReactNode;\n}\n\n/**\n * A toolbar button that fans out a horizontal panel of sub-tool buttons when clicked.\n *\n * Place this inside a vertical {@link Toolbar}. When the button is clicked, a pill-shaped\n * panel slides out to the side (right by default) containing the provided children.\n * The panel animates in/out using a clip-path reveal transition.\n *\n * - Clicking the button again closes the panel\n * - Clicking anywhere outside the panel also closes it\n */\nexport const ToolbarFanOutItem = ({\n icon,\n tooltip,\n tooltipPosition = 'right',\n fanOutDirection = 'right',\n className,\n pt,\n children,\n}: ToolbarFanOutItemProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [isSettled, setIsSettled] = useState(false);\n const isToolbarItemVisible = useToolbarItemVisibility();\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const rovingTrigger = useRovingTool<HTMLButtonElement>(pt?.trigger?.tabIndex, pt?.trigger?.onFocus);\n const rovingTriggerRef = rovingTrigger.ref;\n const setTriggerRef = useCallback((element: HTMLButtonElement | null) => {\n triggerRef.current = element;\n if (typeof rovingTriggerRef === 'function') rovingTriggerRef(element);\n }, [rovingTriggerRef]);\n const panelRef = useRef<HTMLDivElement>(null);\n const generatedPanelId = useId();\n const panelId = pt?.panel?.id ?? generatedPanelId;\n\n // A settled panel has `clip-path: none`, which cannot interpolate — closing\n // straight from it would snap the panel shut instead of wiping it closed.\n // Put an equivalent inset back and let the browser observe it (the forced\n // reflow) before React removes the visible class, so the close transition\n // has an interpolable starting value.\n const collapse = useCallback(() => {\n const panel = panelRef.current;\n if (panel && panel.classList.contains('toolbar-fanout-panel--settled')) {\n panel.style.setProperty('clip-path', 'inset(0 0 0 0 round 1rem)');\n panel.style.setProperty('transition', 'none');\n void panel.offsetWidth;\n panel.style.removeProperty('transition');\n panel.style.removeProperty('clip-path');\n }\n setIsSettled(false);\n setIsExpanded(false);\n }, []);\n\n const handleToggle = () => {\n if (isExpanded) {\n collapse();\n } else {\n setIsExpanded(true);\n }\n };\n\n const handleTransitionEnd = (event: React.TransitionEvent<HTMLDivElement>) => {\n if (\n event.target === panelRef.current &&\n event.propertyName === 'clip-path' &&\n isExpanded\n ) {\n setIsSettled(true);\n }\n };\n\n // Close the fan-out when clicking outside\n useEffect(() => {\n if (!isExpanded) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n collapse();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n collapse();\n window.setTimeout(() => triggerRef.current?.focus(), 0);\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape, true);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape, true);\n };\n }, [isExpanded, collapse]);\n\n const activeClass = isExpanded ? 'toolbar-button--active' : '';\n const panelVisibleClass = isExpanded ? 'toolbar-fanout-panel--visible' : '';\n const panelSettledClass =\n isExpanded && isSettled ? 'toolbar-fanout-panel--settled' : '';\n const directionClass = `toolbar-fanout-panel--${fanOutDirection}`;\n\n return (\n <div\n {...pt?.root}\n className={`toolbar-fanout-item ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='fanout-root'\n data-open={isExpanded || undefined}\n ref={containerRef}\n >\n <Tooltip\n content={tooltip}\n position={tooltipPosition}\n disabled={isExpanded || !isToolbarItemVisible}\n >\n <button\n {...pt?.trigger}\n tabIndex={rovingTrigger.tabIndex}\n onFocus={rovingTrigger.onFocus}\n ref={setTriggerRef}\n type='button'\n aria-label={tooltip}\n aria-expanded={isExpanded}\n aria-controls={panelId}\n onClick={handleToggle}\n className={`toolbar-button cratis:w-10 cratis:h-10 cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${pt?.trigger?.className ?? ''}`}\n data-cratis-part='fanout-trigger'\n data-open={isExpanded || undefined}\n >\n <IconDisplay icon={icon} className='cratis:text-lg' />\n </button>\n </Tooltip>\n <div\n {...pt?.panel}\n id={panelId}\n role='group'\n aria-label={tooltip}\n ref={panelRef}\n className={`toolbar-fanout-panel ${directionClass} ${panelVisibleClass} ${panelSettledClass} ${pt?.panel?.className ?? ''}`}\n data-cratis-part='fanout-panel'\n data-expanded={isExpanded || undefined}\n data-open={isExpanded || undefined}\n data-direction={fanOutDirection}\n data-settled={isSettled || undefined}\n aria-hidden={!isExpanded}\n inert={!isExpanded}\n onTransitionEnd={handleTransitionEnd}\n >\n <ToolbarItemVisibilityProvider value={isExpanded && isToolbarItemVisible}>\n {children}\n </ToolbarItemVisibilityProvider>\n </div>\n </div>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":";;;;;;;AAmEO,MAAM,iBAAiB,GAAG,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,eAAe,GAAG,OAAO,EACzB,eAAe,GAAG,OAAO,EACzB,SAAS,EACT,EAAE,EACF,QAAQ,GACa,KAAI;IACzB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;IACnD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AACjD,IAAA,MAAM,oBAAoB,GAAG,wBAAwB,EAAE;AACvD,IAAA,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC;AACjD,IAAA,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC;AAClD,IAAA,MAAM,aAAa,GAAG,aAAa,CAAoB,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC;AACnG,IAAA,MAAM,gBAAgB,GAAG,aAAa,CAAC,GAAG;AAC1C,IAAA,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,OAAiC,KAAI;AACpE,QAAA,UAAU,CAAC,OAAO,GAAG,OAAO;QAC5B,IAAI,OAAO,gBAAgB,KAAK,UAAU;YAAE,gBAAgB,CAAC,OAAO,CAAC;AACzE,IAAA,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;AACtB,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAiB,IAAI,CAAC;AAC7C,IAAA,MAAM,gBAAgB,GAAG,KAAK,EAAE;IAChC,MAAM,OAAO,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,gBAAgB;AAOjD,IAAA,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAK;AAC9B,QAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO;QAC9B,IAAI,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,+BAA+B,CAAC,EAAE;YACpE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,2BAA2B,CAAC;YACjE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC;YAC7C,KAAK,KAAK,CAAC,WAAW;AACtB,YAAA,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC;AACxC,YAAA,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC;QAC3C;QACA,YAAY,CAAC,KAAK,CAAC;QACnB,aAAa,CAAC,KAAK,CAAC;IACxB,CAAC,EAAE,EAAE,CAAC;IAEN,MAAM,YAAY,GAAG,MAAK;QACtB,IAAI,UAAU,EAAE;AACZ,YAAA,QAAQ,EAAE;QACd;aAAO;YACH,aAAa,CAAC,IAAI,CAAC;QACvB;AACJ,IAAA,CAAC;AAED,IAAA,MAAM,mBAAmB,GAAG,CAAC,KAA4C,KAAI;AACzE,QAAA,IACI,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,OAAO;YACjC,KAAK,CAAC,YAAY,KAAK,WAAW;AAClC,YAAA,UAAU,EACZ;YACE,YAAY,CAAC,IAAI,CAAC;QACtB;AACJ,IAAA,CAAC;IAGD,SAAS,CAAC,MAAK;AACX,QAAA,IAAI,CAAC,UAAU;YAAE;AAEjB,QAAA,MAAM,kBAAkB,GAAG,CAAC,KAAiB,KAAI;YAC7C,IACI,YAAY,CAAC,OAAO;gBACpB,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAc,CAAC,EACtD;AACE,gBAAA,QAAQ,EAAE;YACd;AACJ,QAAA,CAAC;AAED,QAAA,MAAM,YAAY,GAAG,CAAC,KAAoB,KAAI;AAC1C,YAAA,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ;gBAAE;YAC5B,KAAK,CAAC,cAAc,EAAE;YACtB,KAAK,CAAC,eAAe,EAAE;AACvB,YAAA,QAAQ,EAAE;AACV,YAAA,MAAM,CAAC,UAAU,CAAC,MAAM,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AAC3D,QAAA,CAAC;AAED,QAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,kBAAkB,CAAC;QAC1D,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC;AACxD,QAAA,OAAO,MAAK;AACR,YAAA,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,CAAC;YAC7D,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC;AAC/D,QAAA,CAAC;AACL,IAAA,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAE1B,MAAM,WAAW,GAAG,UAAU,GAAG,wBAAwB,GAAG,EAAE;IAC9D,MAAM,iBAAiB,GAAG,UAAU,GAAG,+BAA+B,GAAG,EAAE;AAC3E,IAAA,MAAM,iBAAiB,GACnB,UAAU,IAAI,SAAS,GAAG,+BAA+B,GAAG,EAAE;AAClE,IAAA,MAAM,cAAc,GAAG,CAAA,sBAAA,EAAyB,eAAe,EAAE;IAEjE,QACIA,iBACQ,EAAE,EAAE,IAAI,EACZ,SAAS,EAAE,CAAA,oBAAA,EAAuB,EAAE,EAAE,IAAI,EAAE,SAAS,IAAI,EAAE,IAAI,SAAS,IAAI,EAAE,CAAA,CAAE,EAAA,kBAAA,EAC/D,aAAa,eACnB,UAAU,IAAI,SAAS,EAClC,GAAG,EAAE,YAAY,EAAA,QAAA,EAAA,CAEjBC,IAAC,OAAO,EAAA,EACJ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,UAAU,IAAI,CAAC,oBAAoB,EAAA,QAAA,EAE7CA,GAAA,CAAA,QAAA,EAAA,EAAA,GACQ,EAAE,EAAE,OAAO,EACf,QAAQ,EAAE,aAAa,CAAC,QAAQ,EAChC,OAAO,EAAE,aAAa,CAAC,OAAO,EAC9B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAC,QAAQ,EAAA,YAAA,EACD,OAAO,mBACJ,UAAU,EAAA,eAAA,EACV,OAAO,EACtB,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,CAAA,qIAAA,EAAwI,WAAW,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,IAAI,EAAE,CAAA,CAAE,EAAA,kBAAA,EAC/K,gBAAgB,EAAA,WAAA,EACtB,UAAU,IAAI,SAAS,EAAA,QAAA,EAElCA,IAAC,WAAW,EAAA,EAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAC,gBAAgB,EAAA,CAAG,EAAA,CACjD,GACH,EACVA,GAAA,CAAA,KAAA,EAAA,EAAA,GACQ,EAAE,EAAE,KAAK,EACb,EAAE,EAAE,OAAO,EACX,IAAI,EAAC,OAAO,EAAA,YAAA,EACA,OAAO,EACnB,GAAG,EAAE,QAAQ,EACb,SAAS,EAAE,CAAA,qBAAA,EAAwB,cAAc,IAAI,iBAAiB,CAAA,CAAA,EAAI,iBAAiB,CAAA,CAAA,EAAI,EAAE,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA,CAAE,sBAC1G,cAAc,EAAA,eAAA,EAChB,UAAU,IAAI,SAAS,eAC3B,UAAU,IAAI,SAAS,EAAA,gBAAA,EAClB,eAAe,kBACjB,SAAS,IAAI,SAAS,EAAA,aAAA,EACvB,CAAC,UAAU,EACxB,KAAK,EAAE,CAAC,UAAU,EAClB,eAAe,EAAE,mBAAmB,EAAA,QAAA,EAEpCA,GAAA,CAAC,6BAA6B,EAAA,EAAC,KAAK,EAAE,UAAU,IAAI,oBAAoB,EAAA,QAAA,EACnE,QAAQ,EAAA,CACmB,EAAA,CAC9B,CAAA,EAAA,CACJ;AAEd;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolbarFolder.d.ts","sourceRoot":"","sources":["../../../Toolbar/ToolbarFolder.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEH,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"ToolbarFolder.d.ts","sourceRoot":"","sources":["../../../Toolbar/ToolbarFolder.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEH,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,SAAS,EAOjB,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAgB,CAAC;AAE3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAmB,CAAC;AAMzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAAwB,CAAC;AAEhE,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IAC/B,+CAA+C;IAC/C,IAAI,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IACtC,6BAA6B;IAC7B,OAAO,CAAC,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC;IAClD,2BAA2B;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;CAC1C;AAED,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IAC/B,wDAAwD;IACxD,IAAI,EAAE,IAAI,CAAC;IAEX,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IAEd,iFAAiF;IACjF,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAEnC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;IAEzB,6GAA6G;IAC7G,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,gCAAgC;IAChC,EAAE,CAAC,EAAE,kBAAkB,CAAC;IAExB,6DAA6D;IAC7D,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,kGAUvB,kBAAkB,gCAkIpB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useRef, useId, useMemo, Children, useEffect } from 'react';
|
|
2
|
+
import { useState, useRef, useCallback, useId, useMemo, Children, useEffect } from 'react';
|
|
3
|
+
import { useRovingTool } from '../Common/ToolbarRovingContext.js';
|
|
3
4
|
import { IconDisplay } from '../Common/Icon.js';
|
|
4
5
|
import { Tooltip } from '../Common/Tooltip.js';
|
|
5
6
|
import { ToolbarFolderContext } from './ToolbarFolderContext.js';
|
|
@@ -10,6 +11,13 @@ const ToolbarFolder = ({ icon, title, tooltipPosition = 'right', folderDirection
|
|
|
10
11
|
const isToolbarItemVisible = useToolbarItemVisibility();
|
|
11
12
|
const containerRef = useRef(null);
|
|
12
13
|
const triggerRef = useRef(null);
|
|
14
|
+
const rovingTrigger = useRovingTool(pt?.trigger?.tabIndex, pt?.trigger?.onFocus);
|
|
15
|
+
const rovingTriggerRef = rovingTrigger.ref;
|
|
16
|
+
const setTriggerRef = useCallback((element) => {
|
|
17
|
+
triggerRef.current = element;
|
|
18
|
+
if (typeof rovingTriggerRef === 'function')
|
|
19
|
+
rovingTriggerRef(element);
|
|
20
|
+
}, [rovingTriggerRef]);
|
|
13
21
|
const generatedPanelId = useId();
|
|
14
22
|
const panelId = pt?.panel?.id ?? generatedPanelId;
|
|
15
23
|
const items = useMemo(() => Children.toArray(children).filter((child) => child !== null && child !== undefined), [children]);
|
|
@@ -51,7 +59,7 @@ const ToolbarFolder = ({ icon, title, tooltipPosition = 'right', folderDirection
|
|
|
51
59
|
const panelVisibleClass = isExpanded ? 'toolbar-folder-panel--visible' : '';
|
|
52
60
|
const directionClass = `toolbar-folder-panel--${folderDirection}`;
|
|
53
61
|
const modeClass = mode === 'list' ? 'toolbar-folder-panel--list' : '';
|
|
54
|
-
return (jsx(ToolbarFolderContext.Provider, { value: mode, children: jsxs("div", { ...pt?.root, className: `toolbar-folder-item ${pt?.root?.className ?? ''} ${className ?? ''}`, "data-cratis-part": 'toolbar-folder', "data-open": isExpanded || undefined, ref: containerRef, children: [jsx(Tooltip, { content: title, position: tooltipPosition, disabled: isExpanded || !isToolbarItemVisible, children: jsx("button", { ...pt?.trigger, ref:
|
|
62
|
+
return (jsx(ToolbarFolderContext.Provider, { value: mode, children: jsxs("div", { ...pt?.root, className: `toolbar-folder-item ${pt?.root?.className ?? ''} ${className ?? ''}`, "data-cratis-part": 'toolbar-folder', "data-open": isExpanded || undefined, ref: containerRef, children: [jsx(Tooltip, { content: title, position: tooltipPosition, disabled: isExpanded || !isToolbarItemVisible, children: jsx("button", { ...pt?.trigger, tabIndex: rovingTrigger.tabIndex, onFocus: rovingTrigger.onFocus, ref: setTriggerRef, type: 'button', "aria-label": title, "aria-expanded": isExpanded, "aria-controls": panelId, onClick: toggleExpanded, className: `toolbar-button cratis:w-10 cratis:h-10 cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${pt?.trigger?.className ?? ''}`, "data-cratis-part": 'toolbar-folder-trigger', "data-open": isExpanded || undefined, children: jsx(IconDisplay, { icon: icon, className: 'cratis:text-lg' }) }) }), jsx("div", { ...pt?.panel, id: panelId, role: 'group', "aria-label": title, className: `toolbar-folder-panel ${directionClass} ${panelVisibleClass} ${modeClass} ${pt?.panel?.className ?? ''}`, style: {
|
|
55
63
|
...pt?.panel?.style,
|
|
56
64
|
...(mode === 'grid'
|
|
57
65
|
? {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolbarFolder.js","sources":["../../../Toolbar/ToolbarFolder.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport {\n Children,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { IconDisplay } from '../Common/Icon';\nimport type { Icon } from '../Common/Icon';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\nimport { ToolbarFolderContext } from './ToolbarFolderContext';\nimport {\n ToolbarItemVisibilityProvider,\n useToolbarItemVisibility,\n} from './ToolbarItemVisibilityContext';\nimport type { ToolbarFolderMode } from './ToolbarFolderContext';\n\n/** Stable part attributes for {@link ToolbarFolder}. */\nexport interface ToolbarFolderParts {\n /** Folder composition and measurement root. */\n root?: HTMLAttributes<HTMLDivElement>;\n /** Native folder trigger. */\n trigger?: ButtonHTMLAttributes<HTMLButtonElement>;\n /** Expanded item panel. */\n panel?: HTMLAttributes<HTMLDivElement>;\n}\n\n/** Props for the {@link ToolbarFolder} component. */\nexport interface ToolbarFolderProps {\n /** The icon to display on the folder trigger button. */\n icon: Icon;\n\n /** Title text shown when hovering over the folder trigger button. */\n title: string;\n\n /** Position of the tooltip relative to the trigger button (default: 'right'). */\n tooltipPosition?: TooltipPosition;\n\n /** Direction the folder opens from the trigger button (default: 'right'). */\n folderDirection?: 'right' | 'left';\n\n /**\n * Display mode for the folder's expanded panel (default: `'grid'`).\n *\n * - `'grid'` — items are arranged in a balanced grid (existing behaviour).\n * - `'list'` — items are stacked vertically with the icon and title label shown side by side.\n */\n mode?: ToolbarFolderMode;\n\n /** Maximum number of columns to render before adding more rows (default: 5). Only applies to `grid` mode. */\n maxColumns?: number;\n\n /** Extra class name for the folder root. */\n className?: string;\n\n /** Stable folder attributes. */\n pt?: ToolbarFolderParts;\n\n /** The toolbar buttons shown when the folder is expanded. */\n children: ReactNode;\n}\n\n/**\n * A toolbar folder that reveals a panel of buttons when clicked.\n *\n * **Grid mode** (default): items are arranged in a balanced grid that grows naturally as\n * more items are added and keeps a compact footprint for small sets.\n *\n * **List mode**: items are stacked vertically with their icon and title label rendered\n * side by side — useful when labels add important context to icon-only buttons.\n */\nexport const ToolbarFolder = ({\n icon,\n title,\n tooltipPosition = 'right',\n folderDirection = 'right',\n mode = 'grid',\n maxColumns = 5,\n className,\n pt,\n children,\n}: ToolbarFolderProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const isToolbarItemVisible = useToolbarItemVisibility();\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const generatedPanelId = useId();\n const panelId = pt?.panel?.id ?? generatedPanelId;\n\n const items = useMemo(\n () =>\n Children.toArray(children).filter(\n (child) => child !== null && child !== undefined,\n ),\n [children],\n );\n const itemCount = Math.max(1, items.length);\n\n const columns = useMemo(() => {\n const upperBound = Math.max(1, maxColumns);\n const balancedColumns = Math.ceil(Math.sqrt(itemCount));\n return Math.min(upperBound, balancedColumns);\n }, [itemCount, maxColumns]);\n\n const toggleExpanded = () => {\n setIsExpanded((current) => !current);\n };\n\n useEffect(() => {\n if (!isExpanded) {\n return;\n }\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n setIsExpanded(false);\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n setIsExpanded(false);\n window.setTimeout(() => triggerRef.current?.focus(), 0);\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape, true);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape, true);\n };\n }, [isExpanded]);\n\n const activeClass = isExpanded ? 'toolbar-button--active' : '';\n const panelVisibleClass = isExpanded ? 'toolbar-folder-panel--visible' : '';\n const directionClass = `toolbar-folder-panel--${folderDirection}`;\n const modeClass = mode === 'list' ? 'toolbar-folder-panel--list' : '';\n\n return (\n <ToolbarFolderContext.Provider value={mode}>\n <div\n {...pt?.root}\n className={`toolbar-folder-item ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='toolbar-folder'\n data-open={isExpanded || undefined}\n ref={containerRef}\n >\n <Tooltip\n content={title}\n position={tooltipPosition}\n disabled={isExpanded || !isToolbarItemVisible}\n >\n <button\n {...pt?.trigger}\n ref={triggerRef}\n type='button'\n aria-label={title}\n aria-expanded={isExpanded}\n aria-controls={panelId}\n onClick={toggleExpanded}\n className={`toolbar-button cratis:w-10 cratis:h-10 cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${pt?.trigger?.className ?? ''}`}\n data-cratis-part='toolbar-folder-trigger'\n data-open={isExpanded || undefined}\n >\n <IconDisplay icon={icon} className='cratis:text-lg' />\n </button>\n </Tooltip>\n <div\n {...pt?.panel}\n id={panelId}\n role='group'\n aria-label={title}\n className={`toolbar-folder-panel ${directionClass} ${panelVisibleClass} ${modeClass} ${pt?.panel?.className ?? ''}`}\n style={{\n ...pt?.panel?.style,\n ...(mode === 'grid'\n ? {\n gridTemplateColumns: `repeat(${columns}, minmax(2.5rem, 2.5rem))`,\n }\n : {}),\n }}\n data-cratis-part='toolbar-folder-panel'\n data-expanded={isExpanded || undefined}\n data-open={isExpanded || undefined}\n data-direction={folderDirection}\n data-mode={mode}\n aria-hidden={!isExpanded}\n inert={!isExpanded}\n >\n <ToolbarItemVisibilityProvider\n value={isExpanded && isToolbarItemVisible}\n >\n {items}\n </ToolbarItemVisibilityProvider>\n </div>\n </div>\n </ToolbarFolderContext.Provider>\n );\n};\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ToolbarFolder.js","sources":["../../../Toolbar/ToolbarFolder.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport {\n Children,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n useEffect,\n useId,\n useMemo,\n useRef,\n useCallback,\n useState,\n} from 'react';\nimport { useRovingTool } from '../Common/ToolbarRovingContext';\nimport { IconDisplay } from '../Common/Icon';\nimport type { Icon } from '../Common/Icon';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\nimport { ToolbarFolderContext } from './ToolbarFolderContext';\nimport {\n ToolbarItemVisibilityProvider,\n useToolbarItemVisibility,\n} from './ToolbarItemVisibilityContext';\nimport type { ToolbarFolderMode } from './ToolbarFolderContext';\n\n/** Stable part attributes for {@link ToolbarFolder}. */\nexport interface ToolbarFolderParts {\n /** Folder composition and measurement root. */\n root?: HTMLAttributes<HTMLDivElement>;\n /** Native folder trigger. */\n trigger?: ButtonHTMLAttributes<HTMLButtonElement>;\n /** Expanded item panel. */\n panel?: HTMLAttributes<HTMLDivElement>;\n}\n\n/** Props for the {@link ToolbarFolder} component. */\nexport interface ToolbarFolderProps {\n /** The icon to display on the folder trigger button. */\n icon: Icon;\n\n /** Title text shown when hovering over the folder trigger button. */\n title: string;\n\n /** Position of the tooltip relative to the trigger button (default: 'right'). */\n tooltipPosition?: TooltipPosition;\n\n /** Direction the folder opens from the trigger button (default: 'right'). */\n folderDirection?: 'right' | 'left';\n\n /**\n * Display mode for the folder's expanded panel (default: `'grid'`).\n *\n * - `'grid'` — items are arranged in a balanced grid (existing behaviour).\n * - `'list'` — items are stacked vertically with the icon and title label shown side by side.\n */\n mode?: ToolbarFolderMode;\n\n /** Maximum number of columns to render before adding more rows (default: 5). Only applies to `grid` mode. */\n maxColumns?: number;\n\n /** Extra class name for the folder root. */\n className?: string;\n\n /** Stable folder attributes. */\n pt?: ToolbarFolderParts;\n\n /** The toolbar buttons shown when the folder is expanded. */\n children: ReactNode;\n}\n\n/**\n * A toolbar folder that reveals a panel of buttons when clicked.\n *\n * **Grid mode** (default): items are arranged in a balanced grid that grows naturally as\n * more items are added and keeps a compact footprint for small sets.\n *\n * **List mode**: items are stacked vertically with their icon and title label rendered\n * side by side — useful when labels add important context to icon-only buttons.\n */\nexport const ToolbarFolder = ({\n icon,\n title,\n tooltipPosition = 'right',\n folderDirection = 'right',\n mode = 'grid',\n maxColumns = 5,\n className,\n pt,\n children,\n}: ToolbarFolderProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const isToolbarItemVisible = useToolbarItemVisibility();\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const rovingTrigger = useRovingTool<HTMLButtonElement>(pt?.trigger?.tabIndex, pt?.trigger?.onFocus);\n const rovingTriggerRef = rovingTrigger.ref;\n const setTriggerRef = useCallback((element: HTMLButtonElement | null) => {\n triggerRef.current = element;\n if (typeof rovingTriggerRef === 'function') rovingTriggerRef(element);\n }, [rovingTriggerRef]);\n const generatedPanelId = useId();\n const panelId = pt?.panel?.id ?? generatedPanelId;\n\n const items = useMemo(\n () =>\n Children.toArray(children).filter(\n (child) => child !== null && child !== undefined,\n ),\n [children],\n );\n const itemCount = Math.max(1, items.length);\n\n const columns = useMemo(() => {\n const upperBound = Math.max(1, maxColumns);\n const balancedColumns = Math.ceil(Math.sqrt(itemCount));\n return Math.min(upperBound, balancedColumns);\n }, [itemCount, maxColumns]);\n\n const toggleExpanded = () => {\n setIsExpanded((current) => !current);\n };\n\n useEffect(() => {\n if (!isExpanded) {\n return;\n }\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n containerRef.current &&\n !containerRef.current.contains(event.target as Node)\n ) {\n setIsExpanded(false);\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n setIsExpanded(false);\n window.setTimeout(() => triggerRef.current?.focus(), 0);\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape, true);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape, true);\n };\n }, [isExpanded]);\n\n const activeClass = isExpanded ? 'toolbar-button--active' : '';\n const panelVisibleClass = isExpanded ? 'toolbar-folder-panel--visible' : '';\n const directionClass = `toolbar-folder-panel--${folderDirection}`;\n const modeClass = mode === 'list' ? 'toolbar-folder-panel--list' : '';\n\n return (\n <ToolbarFolderContext.Provider value={mode}>\n <div\n {...pt?.root}\n className={`toolbar-folder-item ${pt?.root?.className ?? ''} ${className ?? ''}`}\n data-cratis-part='toolbar-folder'\n data-open={isExpanded || undefined}\n ref={containerRef}\n >\n <Tooltip\n content={title}\n position={tooltipPosition}\n disabled={isExpanded || !isToolbarItemVisible}\n >\n <button\n {...pt?.trigger}\n tabIndex={rovingTrigger.tabIndex}\n onFocus={rovingTrigger.onFocus}\n ref={setTriggerRef}\n type='button'\n aria-label={title}\n aria-expanded={isExpanded}\n aria-controls={panelId}\n onClick={toggleExpanded}\n className={`toolbar-button cratis:w-10 cratis:h-10 cratis:flex cratis:items-center cratis:justify-center cratis:rounded-lg cratis:cursor-pointer ${activeClass} ${pt?.trigger?.className ?? ''}`}\n data-cratis-part='toolbar-folder-trigger'\n data-open={isExpanded || undefined}\n >\n <IconDisplay icon={icon} className='cratis:text-lg' />\n </button>\n </Tooltip>\n <div\n {...pt?.panel}\n id={panelId}\n role='group'\n aria-label={title}\n className={`toolbar-folder-panel ${directionClass} ${panelVisibleClass} ${modeClass} ${pt?.panel?.className ?? ''}`}\n style={{\n ...pt?.panel?.style,\n ...(mode === 'grid'\n ? {\n gridTemplateColumns: `repeat(${columns}, minmax(2.5rem, 2.5rem))`,\n }\n : {}),\n }}\n data-cratis-part='toolbar-folder-panel'\n data-expanded={isExpanded || undefined}\n data-open={isExpanded || undefined}\n data-direction={folderDirection}\n data-mode={mode}\n aria-hidden={!isExpanded}\n inert={!isExpanded}\n >\n <ToolbarItemVisibilityProvider\n value={isExpanded && isToolbarItemVisible}\n >\n {items}\n </ToolbarItemVisibilityProvider>\n </div>\n </div>\n </ToolbarFolderContext.Provider>\n );\n};\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cratis/components",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.21.0",
|
|
4
4
|
"description": "React components for CQRS and event-sourced apps — command dialogs, typed forms, and query-backed data tables for Cratis Arc",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -258,6 +258,9 @@
|
|
|
258
258
|
"compile": "yarn generate-parts && node ../scripts/run-typescript.mjs -p tsconfig.json -noEmit && yarn g:lint",
|
|
259
259
|
"copy-css": "./scripts/copy-css.sh",
|
|
260
260
|
"verify-exports": "node ./scripts/verify-exports.mjs",
|
|
261
|
+
"verify-api-surface": "node ./scripts/verify-api-surface.mjs",
|
|
262
|
+
"generate-api-surface": "node ./scripts/verify-api-surface.mjs --update",
|
|
263
|
+
"report-api-compatibility": "node ./scripts/report-api-compatibility.mjs",
|
|
261
264
|
"verify-source-maps": "node ./scripts/verify-source-maps.mjs",
|
|
262
265
|
"verify-package-archive": "node ./scripts/verify-package-archive.mjs",
|
|
263
266
|
"verify-packed-css": "node ./scripts/verify-packed-css.mjs",
|
|
@@ -278,7 +281,7 @@
|
|
|
278
281
|
"lint": "yarn g:lint",
|
|
279
282
|
"lint:ci": "yarn g:lint:ci",
|
|
280
283
|
"test": "yarn g:test",
|
|
281
|
-
"ci": "yarn generate-parts && yarn verify-parts-manifest && yarn verify-api-docs && yarn g:ci && yarn typecheck-stories && yarn g:build && yarn verify-renderer-contracts && yarn verify-package-graph-report && yarn verify-packed-css && yarn verify-source-maps",
|
|
284
|
+
"ci": "yarn generate-parts && yarn verify-parts-manifest && yarn verify-api-docs && yarn g:ci && yarn typecheck-stories && yarn g:build && yarn verify-renderer-contracts && yarn verify-package-graph-report && yarn verify-packed-css && yarn verify-source-maps && yarn verify-api-surface",
|
|
282
285
|
"up": "yarn g:up",
|
|
283
286
|
"dev": "yarn workspace @cratis/components.storybook dev",
|
|
284
287
|
"build-storybook": "yarn workspace @cratis/components.storybook build"
|