@cratis/components 1.0.5 → 1.1.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.
Files changed (64) hide show
  1. package/dist/cjs/Common/Tooltip.css +10 -0
  2. package/dist/cjs/Common/Tooltip.js +17 -0
  3. package/dist/cjs/Common/Tooltip.js.map +1 -0
  4. package/dist/cjs/Common/index.js +2 -0
  5. package/dist/cjs/Common/index.js.map +1 -1
  6. package/dist/cjs/Toolbar/Toolbar.css +131 -0
  7. package/dist/cjs/Toolbar/Toolbar.js +9 -0
  8. package/dist/cjs/Toolbar/Toolbar.js.map +1 -0
  9. package/dist/cjs/Toolbar/ToolbarButton.js +12 -0
  10. package/dist/cjs/Toolbar/ToolbarButton.js.map +1 -0
  11. package/dist/cjs/Toolbar/ToolbarContext.js +6 -0
  12. package/dist/cjs/Toolbar/ToolbarContext.js.map +1 -0
  13. package/dist/cjs/Toolbar/ToolbarFanOutItem.js +33 -0
  14. package/dist/cjs/Toolbar/ToolbarFanOutItem.js.map +1 -0
  15. package/dist/cjs/Toolbar/ToolbarSection.js +32 -0
  16. package/dist/cjs/Toolbar/ToolbarSection.js.map +1 -0
  17. package/dist/cjs/Toolbar/index.js +16 -0
  18. package/dist/cjs/Toolbar/index.js.map +1 -0
  19. package/dist/cjs/index.js +2 -0
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/esm/Common/Tooltip.css +10 -0
  22. package/dist/esm/Common/Tooltip.d.ts +10 -0
  23. package/dist/esm/Common/Tooltip.d.ts.map +1 -0
  24. package/dist/esm/Common/Tooltip.js +15 -0
  25. package/dist/esm/Common/Tooltip.js.map +1 -0
  26. package/dist/esm/Common/index.d.ts +1 -0
  27. package/dist/esm/Common/index.d.ts.map +1 -1
  28. package/dist/esm/Common/index.js +1 -0
  29. package/dist/esm/Common/index.js.map +1 -1
  30. package/dist/esm/Toolbar/Toolbar.css +131 -0
  31. package/dist/esm/Toolbar/Toolbar.d.ts +8 -0
  32. package/dist/esm/Toolbar/Toolbar.d.ts.map +1 -0
  33. package/dist/esm/Toolbar/Toolbar.js +7 -0
  34. package/dist/esm/Toolbar/Toolbar.js.map +1 -0
  35. package/dist/esm/Toolbar/Toolbar.stories.d.ts +11 -0
  36. package/dist/esm/Toolbar/Toolbar.stories.d.ts.map +1 -0
  37. package/dist/esm/Toolbar/Toolbar.stories.js +53 -0
  38. package/dist/esm/Toolbar/Toolbar.stories.js.map +1 -0
  39. package/dist/esm/Toolbar/ToolbarButton.d.ts +10 -0
  40. package/dist/esm/Toolbar/ToolbarButton.d.ts.map +1 -0
  41. package/dist/esm/Toolbar/ToolbarButton.js +10 -0
  42. package/dist/esm/Toolbar/ToolbarButton.js.map +1 -0
  43. package/dist/esm/Toolbar/ToolbarContext.d.ts +7 -0
  44. package/dist/esm/Toolbar/ToolbarContext.d.ts.map +1 -0
  45. package/dist/esm/Toolbar/ToolbarContext.js +4 -0
  46. package/dist/esm/Toolbar/ToolbarContext.js.map +1 -0
  47. package/dist/esm/Toolbar/ToolbarFanOutItem.d.ts +11 -0
  48. package/dist/esm/Toolbar/ToolbarFanOutItem.d.ts.map +1 -0
  49. package/dist/esm/Toolbar/ToolbarFanOutItem.js +31 -0
  50. package/dist/esm/Toolbar/ToolbarFanOutItem.js.map +1 -0
  51. package/dist/esm/Toolbar/ToolbarSection.d.ts +8 -0
  52. package/dist/esm/Toolbar/ToolbarSection.d.ts.map +1 -0
  53. package/dist/esm/Toolbar/ToolbarSection.js +30 -0
  54. package/dist/esm/Toolbar/ToolbarSection.js.map +1 -0
  55. package/dist/esm/Toolbar/index.d.ts +11 -0
  56. package/dist/esm/Toolbar/index.d.ts.map +1 -0
  57. package/dist/esm/Toolbar/index.js +6 -0
  58. package/dist/esm/Toolbar/index.js.map +1 -0
  59. package/dist/esm/index.d.ts +2 -1
  60. package/dist/esm/index.d.ts.map +1 -1
  61. package/dist/esm/index.js +2 -0
  62. package/dist/esm/index.js.map +1 -1
  63. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  64. package/package.json +6 -1
@@ -0,0 +1,10 @@
1
+ /* Copyright (c) Cratis. All rights reserved. */
2
+ /* Licensed under the MIT license. See LICENSE file in the project root for full license information. */
3
+
4
+ /* ── Tooltip bubble ──────────────────────────────────────────────────────── */
5
+ .tooltip-bubble {
6
+ background: var(--surface-100);
7
+ color: var(--text-color);
8
+ border: 1px solid var(--surface-border);
9
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
10
+ }
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ require('./Tooltip.css');
5
+
6
+ const POSITION_CLASSES = {
7
+ right: 'left-full ml-2 top-1/2 -translate-y-1/2',
8
+ left: 'right-full mr-2 top-1/2 -translate-y-1/2',
9
+ top: 'bottom-full mb-2 left-1/2 -translate-x-1/2',
10
+ bottom: 'top-full mt-2 left-1/2 -translate-x-1/2',
11
+ };
12
+ const Tooltip = ({ content, position = 'top', children }) => (jsxRuntime.jsxs("div", { className: 'relative group inline-flex', children: [children, jsxRuntime.jsx("div", { role: 'tooltip', className: `tooltip-bubble pointer-events-none absolute ${POSITION_CLASSES[position]} z-50
13
+ text-xs px-2 py-1 rounded
14
+ whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-150 delay-200`, style: { fontFamily: 'system-ui, sans-serif' }, children: content })] }));
15
+
16
+ exports.Tooltip = Tooltip;
17
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../Common/Tooltip.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 from 'react';\nimport './Tooltip.css';\n\n/** Position of the tooltip relative to its trigger element. */\nexport type TooltipPosition = 'top' | 'right' | 'bottom' | 'left';\n\n/** Props for the {@link Tooltip} component. */\nexport interface TooltipProps {\n /** The text to display inside the tooltip. */\n content: string;\n /** Where the tooltip appears relative to the trigger (default: 'top'). */\n position?: TooltipPosition;\n /** The element that triggers the tooltip on hover. */\n children: React.ReactNode;\n}\n\nconst POSITION_CLASSES: Record<TooltipPosition, string> = {\n right: 'left-full ml-2 top-1/2 -translate-y-1/2',\n left: 'right-full mr-2 top-1/2 -translate-y-1/2',\n top: 'bottom-full mb-2 left-1/2 -translate-x-1/2',\n bottom: 'top-full mt-2 left-1/2 -translate-x-1/2',\n};\n\n/**\n * A CSS-only hover tooltip wrapper. Wraps any child element and displays\n * a styled floating label on hover without relying on native browser tooltips.\n */\nexport const Tooltip: React.FC<TooltipProps> = ({ content, position = 'top', children }) => (\n <div className='relative group inline-flex'>\n {children}\n <div\n role='tooltip'\n className={`tooltip-bubble pointer-events-none absolute ${POSITION_CLASSES[position]} z-50\n text-xs px-2 py-1 rounded\n whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-150 delay-200`}\n style={{ fontFamily: 'system-ui, sans-serif' }}\n >\n {content}\n </div>\n </div>\n);\n"],"names":["_jsxs","_jsx"],"mappings":";;;;;AAmBA,MAAM,gBAAgB,GAAoC;AACtD,IAAA,KAAK,EAAG,yCAAyC;AACjD,IAAA,IAAI,EAAI,0CAA0C;AAClD,IAAA,GAAG,EAAK,4CAA4C;AACpD,IAAA,MAAM,EAAE,yCAAyC;CACpD;AAMM,MAAM,OAAO,GAA2B,CAAC,EAAE,OAAO,EAAE,QAAQ,GAAG,KAAK,EAAE,QAAQ,EAAE,MACnFA,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACtC,QAAQ,EACTC,wBACI,IAAI,EAAC,SAAS,EACd,SAAS,EAAE,CAAA,4CAAA,EAA+C,gBAAgB,CAAC,QAAQ,CAAC,CAAA;;AAEc,6GAAA,CAAA,EAClG,KAAK,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE,EAAA,QAAA,EAE7C,OAAO,EAAA,CACN,CAAA,EAAA,CACJ;;;;"}
@@ -3,10 +3,12 @@
3
3
  var ErrorBoundary = require('./ErrorBoundary.js');
4
4
  var Page = require('./Page.js');
5
5
  var FormElement = require('./FormElement.js');
6
+ var Tooltip = require('./Tooltip.js');
6
7
 
7
8
 
8
9
 
9
10
  exports.ErrorBoundary = ErrorBoundary.ErrorBoundary;
10
11
  exports.Page = Page.Page;
11
12
  exports.FormElement = FormElement.FormElement;
13
+ exports.Tooltip = Tooltip.Tooltip;
12
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
@@ -0,0 +1,131 @@
1
+ /* Copyright (c) Cratis. All rights reserved. */
2
+ /* Licensed under the MIT license. See LICENSE file in the project root for full license information. */
3
+
4
+ /* ── Toolbar container ───────────────────────────────────────────────────── */
5
+ .toolbar {
6
+ background: var(--surface-card);
7
+ border: 1px solid var(--surface-border);
8
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
9
+ }
10
+
11
+ /* ── Toolbar button ──────────────────────────────────────────────────────── */
12
+ .toolbar-button {
13
+ color: var(--text-color-secondary);
14
+ background: transparent;
15
+ border: none;
16
+ transition: background 0.15s, color 0.15s;
17
+ }
18
+
19
+ .toolbar-button:hover {
20
+ background: var(--surface-100);
21
+ color: var(--text-color);
22
+ }
23
+
24
+ .toolbar-button--active {
25
+ background: var(--primary-color);
26
+ color: var(--primary-color-text);
27
+ }
28
+
29
+ .toolbar-button--active:hover {
30
+ background: var(--primary-color);
31
+ color: var(--primary-color-text);
32
+ }
33
+
34
+ /* ── Toolbar project name label ──────────────────────────────────────────── */
35
+ .toolbar-project-name {
36
+ padding: 0 8px;
37
+ font-size: 0.875rem;
38
+ font-weight: 500;
39
+ color: var(--text-color);
40
+ white-space: nowrap;
41
+ }
42
+
43
+ /* ── Toolbar section (context switching) ────────────────────────────────── */
44
+
45
+ /*
46
+ * The section is a fixed-size container that transitions smoothly between
47
+ * the dimensions required by each context.
48
+ * overflow is intentionally left as visible so that absolutely-positioned
49
+ * children (e.g. fan-out panels) can extend beyond the section's bounds.
50
+ * Inactive contexts are hidden via opacity/pointer-events, not overflow clipping.
51
+ */
52
+ .toolbar-section {
53
+ position: relative;
54
+ transition:
55
+ width 0.35s cubic-bezier(0.4, 0, 0.2, 1),
56
+ height 0.35s cubic-bezier(0.4, 0, 0.2, 1);
57
+ }
58
+
59
+ /*
60
+ * Every context is absolutely stacked at the top-left of the section.
61
+ * Only the active one is visible; the others fade out and lose pointer events.
62
+ */
63
+ .toolbar-context {
64
+ position: absolute;
65
+ top: 0;
66
+ left: 0;
67
+ transition: opacity 0.2s ease;
68
+ }
69
+
70
+ .toolbar-context--active {
71
+ opacity: 1;
72
+ pointer-events: auto;
73
+ }
74
+
75
+ .toolbar-context--inactive {
76
+ opacity: 0;
77
+ pointer-events: none;
78
+ }
79
+
80
+ /* ── Toolbar fan-out item ────────────────────────────────────────────────── */
81
+
82
+ /*
83
+ * The wrapper provides the positioning context for the absolutely-placed panel.
84
+ */
85
+ .toolbar-fanout-item {
86
+ position: relative;
87
+ }
88
+
89
+ /*
90
+ * The fan-out panel is a floating pill that mirrors the Toolbar container style.
91
+ * When collapsed, it's hidden. When expanded, it appears elevated at the same
92
+ * position as the trigger button, with the trigger button as the first item.
93
+ * Vertically centered with where the collapsed button would be.
94
+ */
95
+ .toolbar-fanout-panel {
96
+ position: absolute;
97
+ top: 50%;
98
+ left: calc(-0.5rem - 1px);
99
+ transform: translateY(-50%);
100
+ display: inline-flex;
101
+ flex-direction: row;
102
+ align-items: center;
103
+ gap: 0.25rem;
104
+ padding: 0.5rem;
105
+ background: var(--surface-card);
106
+ border: 1px solid var(--surface-border);
107
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
108
+ border-radius: 1rem;
109
+ white-space: nowrap;
110
+ z-index: 10;
111
+ pointer-events: none;
112
+ opacity: 0;
113
+ clip-path: inset(0 100% 0 0 round 1rem);
114
+ transition:
115
+ clip-path 0.35s cubic-bezier(0.4, 0, 0.2, 1),
116
+ opacity 0.2s ease;
117
+ }
118
+
119
+ /* Panel fans out to the left — reveal animates right → left */
120
+ .toolbar-fanout-panel--left {
121
+ left: auto;
122
+ right: calc(-0.5rem - 1px);
123
+ clip-path: inset(0 0 0 100% round 1rem);
124
+ }
125
+
126
+ /* Expanded state — fully visible, pointer events restored */
127
+ .toolbar-fanout-panel--visible {
128
+ clip-path: inset(0 0 0 0 round 1rem);
129
+ opacity: 1;
130
+ pointer-events: auto;
131
+ }
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ require('./Toolbar.css');
5
+
6
+ const Toolbar = ({ children, orientation = 'vertical' }) => (jsxRuntime.jsx("div", { className: `toolbar inline-flex ${orientation === 'horizontal' ? 'flex-row' : 'flex-col'} items-center gap-1 p-2 rounded-2xl`, children: children }));
7
+
8
+ exports.Toolbar = Toolbar;
9
+ //# sourceMappingURL=Toolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolbar.js","sources":["../../../Toolbar/Toolbar.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 { ReactNode } from 'react';\nimport './Toolbar.css';\n\n/** Props for the {@link Toolbar} component. */\nexport interface ToolbarProps {\n /** The {@link ToolbarButton} elements to render inside this toolbar group. */\n children: ReactNode;\n /** Layout direction of the toolbar (default: 'vertical'). */\n orientation?: 'vertical' | 'horizontal';\n}\n\n/**\n * A toolbar container that groups icon buttons with a rounded border,\n * mimicking the style of tools panels found in canvas-based applications.\n * Supports both vertical (default) and horizontal orientations.\n */\nexport const Toolbar = ({ children, orientation = 'vertical' }: ToolbarProps) => (\n <div\n className={`toolbar inline-flex ${\n orientation === 'horizontal' ? 'flex-row' : 'flex-col'\n } items-center gap-1 p-2 rounded-2xl`}\n >\n {children}\n </div>\n);\n"],"names":["_jsx"],"mappings":";;;;;AAmBO,MAAM,OAAO,GAAG,CAAC,EAAE,QAAQ,EAAE,WAAW,GAAG,UAAU,EAAgB,MACxEA,cAAA,CAAA,KAAA,EAAA,EACI,SAAS,EAAE,CAAA,oBAAA,EACP,WAAW,KAAK,YAAY,GAAG,UAAU,GAAG,UAChD,CAAA,mCAAA,CAAqC,EAAA,QAAA,EAEpC,QAAQ,EAAA,CACP;;;;"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var Tooltip = require('../Common/Tooltip.js');
5
+
6
+ const ToolbarButton = ({ icon, tooltip, active = false, onClick, tooltipPosition = 'right' }) => {
7
+ const activeClass = active ? 'toolbar-button--active' : '';
8
+ return (jsxRuntime.jsx(Tooltip.Tooltip, { content: tooltip, position: tooltipPosition, children: jsxRuntime.jsx("button", { type: 'button', "aria-label": tooltip, onClick: onClick, className: `toolbar-button w-10 h-10 flex items-center justify-center rounded-lg cursor-pointer ${activeClass}`, children: jsxRuntime.jsx("i", { className: `${icon} text-lg` }) }) }));
9
+ };
10
+
11
+ exports.ToolbarButton = ToolbarButton;
12
+ //# sourceMappingURL=ToolbarButton.js.map
@@ -0,0 +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 { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\n\n/** Props for the {@link ToolbarButton} component. */\nexport interface ToolbarButtonProps {\n /** The PrimeIcons CSS class to use as the icon (e.g. 'pi pi-home'). */\n icon: string;\n\n /** Tooltip text shown when the user hovers over the button. */\n tooltip: 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\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 = ({ icon, tooltip, active = false, onClick, tooltipPosition = 'right' }: ToolbarButtonProps) => {\n const activeClass = active ? 'toolbar-button--active' : '';\n\n return (\n <Tooltip content={tooltip} position={tooltipPosition}>\n <button\n type='button'\n aria-label={tooltip}\n onClick={onClick}\n className={`toolbar-button w-10 h-10 flex items-center justify-center rounded-lg cursor-pointer ${activeClass}`}\n >\n <i className={`${icon} text-lg`} />\n </button>\n </Tooltip>\n );\n};\n"],"names":["_jsx","Tooltip"],"mappings":";;;;;MA4Ba,aAAa,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,EAAsB,KAAI;IACvH,MAAM,WAAW,GAAG,MAAM,GAAG,wBAAwB,GAAG,EAAE;AAE1D,IAAA,QACIA,cAAA,CAACC,eAAO,EAAA,EAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAA,QAAA,EAChDD,cAAA,CAAA,QAAA,EAAA,EACI,IAAI,EAAC,QAAQ,gBACD,OAAO,EACnB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,CAAA,oFAAA,EAAuF,WAAW,EAAE,EAAA,QAAA,EAE/GA,cAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAE,GAAG,IAAI,CAAA,QAAA,CAAU,GAAI,EAAA,CAC9B,EAAA,CACH;AAElB;;;;"}
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ const ToolbarContext = () => null;
4
+
5
+ exports.ToolbarContext = ToolbarContext;
6
+ //# sourceMappingURL=ToolbarContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolbarContext.js","sources":["../../../Toolbar/ToolbarContext.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 { FC, ReactNode } from 'react';\n\n/** Props for the {@link ToolbarContext} component. */\nexport interface ToolbarContextProps {\n /** Unique name identifying this context within a {@link ToolbarSection}. */\n name: string;\n /** The toolbar items to render when this context is active. */\n children: ReactNode;\n}\n\n/**\n * Defines a named context (a set of toolbar items) within a {@link ToolbarSection}.\n * The section renders only the active context at a time and animates between them.\n *\n * This is a data-only component; its rendering is fully managed by {@link ToolbarSection}.\n */\nexport const ToolbarContext: FC<ToolbarContextProps> = () => null;\n"],"names":[],"mappings":";;MAmBa,cAAc,GAA4B,MAAM;;;;"}
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+ var Tooltip = require('../Common/Tooltip.js');
6
+
7
+ const ToolbarFanOutItem = ({ icon, tooltip, tooltipPosition = 'right', fanOutDirection = 'right', children, }) => {
8
+ const [isExpanded, setIsExpanded] = React.useState(false);
9
+ const containerRef = React.useRef(null);
10
+ const handleToggle = () => {
11
+ setIsExpanded(!isExpanded);
12
+ };
13
+ React.useEffect(() => {
14
+ if (!isExpanded)
15
+ return;
16
+ const handleClickOutside = (event) => {
17
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
18
+ setIsExpanded(false);
19
+ }
20
+ };
21
+ document.addEventListener('mousedown', handleClickOutside);
22
+ return () => {
23
+ document.removeEventListener('mousedown', handleClickOutside);
24
+ };
25
+ }, [isExpanded]);
26
+ const activeClass = isExpanded ? 'toolbar-button--active' : '';
27
+ const panelVisibleClass = isExpanded ? 'toolbar-fanout-panel--visible' : '';
28
+ const directionClass = `toolbar-fanout-panel--${fanOutDirection}`;
29
+ return (jsxRuntime.jsxs("div", { className: 'toolbar-fanout-item', ref: containerRef, children: [jsxRuntime.jsx(Tooltip.Tooltip, { content: tooltip, position: tooltipPosition, children: jsxRuntime.jsx("button", { type: 'button', "aria-label": tooltip, "aria-expanded": isExpanded, onClick: handleToggle, className: `toolbar-button w-10 h-10 flex items-center justify-center rounded-lg cursor-pointer ${activeClass}`, children: jsxRuntime.jsx("i", { className: `${icon} text-lg` }) }) }), jsxRuntime.jsx("div", { className: `toolbar-fanout-panel ${directionClass} ${panelVisibleClass}`, children: children })] }));
30
+ };
31
+
32
+ exports.ToolbarFanOutItem = ToolbarFanOutItem;
33
+ //# sourceMappingURL=ToolbarFanOutItem.js.map
@@ -0,0 +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 { ReactNode, useEffect, useRef, useState } from 'react';\nimport { Tooltip } from '../Common/Tooltip';\nimport type { TooltipPosition } from '../Common/Tooltip';\n\n/** Props for the {@link ToolbarFanOutItem} component. */\nexport interface ToolbarFanOutItemProps {\n /** The PrimeIcons CSS class to use as the trigger icon (e.g. 'pi pi-home'). */\n icon: string;\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';\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 children,\n}: ToolbarFanOutItemProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const handleToggle = () => {\n setIsExpanded(!isExpanded);\n };\n\n // Close the fan-out when clicking outside\n useEffect(() => {\n if (!isExpanded) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n setIsExpanded(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [isExpanded]);\n\n const activeClass = isExpanded ? 'toolbar-button--active' : '';\n const panelVisibleClass = isExpanded ? 'toolbar-fanout-panel--visible' : '';\n const directionClass = `toolbar-fanout-panel--${fanOutDirection}`;\n\n return (\n <div className='toolbar-fanout-item' ref={containerRef}>\n <Tooltip content={tooltip} position={tooltipPosition}>\n <button\n type='button'\n aria-label={tooltip}\n aria-expanded={isExpanded}\n onClick={handleToggle}\n className={`toolbar-button w-10 h-10 flex items-center justify-center rounded-lg cursor-pointer ${activeClass}`}\n >\n <i className={`${icon} text-lg`} />\n </button>\n </Tooltip>\n <div className={`toolbar-fanout-panel ${directionClass} ${panelVisibleClass}`}>\n {children}\n </div>\n </div>\n );\n};\n"],"names":["useState","useRef","useEffect","_jsxs","_jsx","Tooltip"],"mappings":";;;;;;MAmCa,iBAAiB,GAAG,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,eAAe,GAAG,OAAO,EACzB,eAAe,GAAG,OAAO,EACzB,QAAQ,GACa,KAAI;IACzB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAGA,cAAQ,CAAC,KAAK,CAAC;AACnD,IAAA,MAAM,YAAY,GAAGC,YAAM,CAAiB,IAAI,CAAC;IAEjD,MAAM,YAAY,GAAG,MAAK;AACtB,QAAA,aAAa,CAAC,CAAC,UAAU,CAAC;AAC9B,IAAA,CAAC;IAGDC,eAAS,CAAC,MAAK;AACX,QAAA,IAAI,CAAC,UAAU;YAAE;AAEjB,QAAA,MAAM,kBAAkB,GAAG,CAAC,KAAiB,KAAI;AAC7C,YAAA,IAAI,YAAY,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAc,CAAC,EAAE;gBAC9E,aAAa,CAAC,KAAK,CAAC;YACxB;AACJ,QAAA,CAAC;AAED,QAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,kBAAkB,CAAC;AAC1D,QAAA,OAAO,MAAK;AACR,YAAA,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,CAAC;AACjE,QAAA,CAAC;AACL,IAAA,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;IAEhB,MAAM,WAAW,GAAG,UAAU,GAAG,wBAAwB,GAAG,EAAE;IAC9D,MAAM,iBAAiB,GAAG,UAAU,GAAG,+BAA+B,GAAG,EAAE;AAC3E,IAAA,MAAM,cAAc,GAAG,CAAA,sBAAA,EAAyB,eAAe,EAAE;AAEjE,IAAA,QACIC,eAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,qBAAqB,EAAC,GAAG,EAAE,YAAY,EAAA,QAAA,EAAA,CAClDC,cAAA,CAACC,eAAO,EAAA,EAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAA,QAAA,EAChDD,cAAA,CAAA,QAAA,EAAA,EACI,IAAI,EAAC,QAAQ,EAAA,YAAA,EACD,OAAO,EAAA,eAAA,EACJ,UAAU,EACzB,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,CAAA,oFAAA,EAAuF,WAAW,CAAA,CAAE,EAAA,QAAA,EAE/GA,cAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAE,CAAA,EAAG,IAAI,UAAU,EAAA,CAAI,EAAA,CAC9B,EAAA,CACH,EACVA,cAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,CAAA,qBAAA,EAAwB,cAAc,CAAA,CAAA,EAAI,iBAAiB,CAAA,CAAE,EAAA,QAAA,EACxE,QAAQ,EAAA,CACP,CAAA,EAAA,CACJ;AAEd;;;;"}
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+
6
+ const ToolbarSection = ({ activeContext, children, orientation = 'vertical' }) => {
7
+ const contextRefs = React.useRef({});
8
+ const [size, setSize] = React.useState(null);
9
+ const contexts = React.Children.toArray(children).filter((child) => React.isValidElement(child) && typeof child.props.name === 'string');
10
+ const effectiveContext = activeContext ?? contexts[0]?.props?.name ?? '';
11
+ const flexClass = orientation === 'horizontal' ? 'flex-row' : 'flex-col';
12
+ const measureAndSetSize = React.useCallback((contextName) => {
13
+ const ref = contextRefs.current[contextName];
14
+ if (ref) {
15
+ setSize({ width: ref.offsetWidth, height: ref.offsetHeight });
16
+ }
17
+ }, []);
18
+ React.useLayoutEffect(() => {
19
+ measureAndSetSize(effectiveContext);
20
+ }, []);
21
+ React.useEffect(() => {
22
+ measureAndSetSize(effectiveContext);
23
+ }, [effectiveContext, measureAndSetSize]);
24
+ return (jsxRuntime.jsx("div", { className: 'toolbar-section', style: size ? { width: size.width, height: size.height } : undefined, children: contexts.map((child) => {
25
+ const { name, children: contextChildren } = child.props;
26
+ const isActive = name === effectiveContext;
27
+ return (jsxRuntime.jsx("div", { ref: (element) => { contextRefs.current[name] = element; }, className: `toolbar-context inline-flex ${flexClass} items-center gap-1 ${isActive ? 'toolbar-context--active' : 'toolbar-context--inactive'}`, children: contextChildren }, name));
28
+ }) }));
29
+ };
30
+
31
+ exports.ToolbarSection = ToolbarSection;
32
+ //# sourceMappingURL=ToolbarSection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolbarSection.js","sources":["../../../Toolbar/ToolbarSection.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 { Children, ReactElement, ReactNode, isValidElement, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\n\nimport type { ToolbarContextProps } from './ToolbarContext';\n\n/** Props for the {@link ToolbarSection} component. */\nexport interface ToolbarSectionProps {\n /**\n * The name of the currently active context.\n * Change this to trigger the fade-out / morph / fade-in animation.\n * Defaults to the first context if not specified.\n */\n activeContext?: string;\n\n /** {@link ToolbarContext} elements that define each context's toolbar items. */\n children: ReactNode;\n\n /** Layout direction matching the parent {@link Toolbar} (default: 'vertical'). */\n orientation?: 'vertical' | 'horizontal';\n}\n\n/**\n * A section within a {@link Toolbar} that supports multiple named contexts.\n *\n * When {@link activeContext} changes:\n * - The current items fade out.\n * - The section smoothly morphs to the dimensions required by the new context.\n * - The new items fade in.\n *\n * Contexts are defined by placing {@link ToolbarContext} children inside this section.\n * Switching contexts only affects this section; other sections are unaffected.\n */\nexport const ToolbarSection = ({ activeContext, children, orientation = 'vertical' }: ToolbarSectionProps) => {\n const contextRefs = useRef<Record<string, HTMLDivElement | null>>({});\n const [size, setSize] = useState<{ width: number; height: number } | null>(null);\n\n const contexts = Children.toArray(children).filter(\n (child): child is ReactElement<ToolbarContextProps> =>\n isValidElement(child) && typeof (child.props as ToolbarContextProps).name === 'string'\n );\n\n // Default to the first context if activeContext is not provided\n const effectiveContext = activeContext ?? (contexts[0]?.props as ToolbarContextProps)?.name ?? '';\n\n const flexClass = orientation === 'horizontal' ? 'flex-row' : 'flex-col';\n\n /** Measure the given context's natural dimensions and update the section size. */\n const measureAndSetSize = useCallback((contextName: string) => {\n const ref = contextRefs.current[contextName];\n if (ref) {\n setSize({ width: ref.offsetWidth, height: ref.offsetHeight });\n }\n }, []);\n\n // Set the initial size synchronously before the first browser paint so there is no layout flash.\n // Empty dependency array is intentional: ongoing context changes are handled by the useEffect below.\n useLayoutEffect(() => {\n measureAndSetSize(effectiveContext);\n }, []); // run only on mount\n\n // After a context switch, let the browser paint the opacity transition first,\n // then update the explicit size so the CSS width/height transition kicks in.\n useEffect(() => {\n measureAndSetSize(effectiveContext);\n }, [effectiveContext, measureAndSetSize]);\n\n return (\n <div\n className='toolbar-section'\n style={size ? { width: size.width, height: size.height } : undefined}\n >\n {contexts.map((child) => {\n const { name, children: contextChildren } = child.props as ToolbarContextProps;\n const isActive = name === effectiveContext;\n\n return (\n <div\n key={name}\n ref={(element) => { contextRefs.current[name] = element; }}\n className={`toolbar-context inline-flex ${flexClass} items-center gap-1 ${\n isActive ? 'toolbar-context--active' : 'toolbar-context--inactive'\n }`}\n >\n {contextChildren}\n </div>\n );\n })}\n </div>\n );\n};\n"],"names":["useRef","useState","Children","isValidElement","useCallback","useLayoutEffect","useEffect","_jsx"],"mappings":";;;;;AAkCO,MAAM,cAAc,GAAG,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,GAAG,UAAU,EAAuB,KAAI;AACzG,IAAA,MAAM,WAAW,GAAGA,YAAM,CAAwC,EAAE,CAAC;IACrE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAGC,cAAQ,CAA2C,IAAI,CAAC;AAEhF,IAAA,MAAM,QAAQ,GAAGC,cAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAC9C,CAAC,KAAK,KACFC,oBAAc,CAAC,KAAK,CAAC,IAAI,OAAQ,KAAK,CAAC,KAA6B,CAAC,IAAI,KAAK,QAAQ,CAC7F;AAGD,IAAA,MAAM,gBAAgB,GAAG,aAAa,IAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAA6B,EAAE,IAAI,IAAI,EAAE;AAEjG,IAAA,MAAM,SAAS,GAAG,WAAW,KAAK,YAAY,GAAG,UAAU,GAAG,UAAU;AAGxE,IAAA,MAAM,iBAAiB,GAAGC,iBAAW,CAAC,CAAC,WAAmB,KAAI;QAC1D,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC;QAC5C,IAAI,GAAG,EAAE;AACL,YAAA,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC;QACjE;IACJ,CAAC,EAAE,EAAE,CAAC;IAINC,qBAAe,CAAC,MAAK;QACjB,iBAAiB,CAAC,gBAAgB,CAAC;IACvC,CAAC,EAAE,EAAE,CAAC;IAINC,eAAS,CAAC,MAAK;QACX,iBAAiB,CAAC,gBAAgB,CAAC;AACvC,IAAA,CAAC,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;AAEzC,IAAA,QACIC,cAAA,CAAA,KAAA,EAAA,EACI,SAAS,EAAC,iBAAiB,EAC3B,KAAK,EAAE,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,EAAA,QAAA,EAEnE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,KAAI;YACpB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC,KAA4B;AAC9E,YAAA,MAAM,QAAQ,GAAG,IAAI,KAAK,gBAAgB;AAE1C,YAAA,QACIA,cAAA,CAAA,KAAA,EAAA,EAEI,GAAG,EAAE,CAAC,OAAO,KAAI,EAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC1D,SAAS,EAAE,+BAA+B,SAAS,CAAA,oBAAA,EAC/C,QAAQ,GAAG,yBAAyB,GAAG,2BAC3C,EAAE,EAAA,QAAA,EAED,eAAe,IANX,IAAI,CAOP;QAEd,CAAC,CAAC,EAAA,CACA;AAEd;;;;"}
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ var Toolbar = require('./Toolbar.js');
4
+ var ToolbarButton = require('./ToolbarButton.js');
5
+ var ToolbarContext = require('./ToolbarContext.js');
6
+ var ToolbarSection = require('./ToolbarSection.js');
7
+ var ToolbarFanOutItem = require('./ToolbarFanOutItem.js');
8
+
9
+
10
+
11
+ exports.Toolbar = Toolbar.Toolbar;
12
+ exports.ToolbarButton = ToolbarButton.ToolbarButton;
13
+ exports.ToolbarContext = ToolbarContext.ToolbarContext;
14
+ exports.ToolbarSection = ToolbarSection.ToolbarSection;
15
+ exports.ToolbarFanOutItem = ToolbarFanOutItem.ToolbarFanOutItem;
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
package/dist/cjs/index.js CHANGED
@@ -12,6 +12,7 @@ var index$8 = require('./ObjectNavigationalBar/index.js');
12
12
  var index$9 = require('./PivotViewer/index.js');
13
13
  var index$a = require('./SchemaEditor/index.js');
14
14
  var index$b = require('./TimeMachine/index.js');
15
+ var index$c = require('./Toolbar/index.js');
15
16
 
16
17
 
17
18
 
@@ -27,4 +28,5 @@ exports.ObjectNavigationalBar = index$8;
27
28
  exports.PivotViewer = index$9;
28
29
  exports.SchemaEditor = index$a;
29
30
  exports.TimeMachine = index$b;
31
+ exports.Toolbar = index$c;
30
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,10 @@
1
+ /* Copyright (c) Cratis. All rights reserved. */
2
+ /* Licensed under the MIT license. See LICENSE file in the project root for full license information. */
3
+
4
+ /* ── Tooltip bubble ──────────────────────────────────────────────────────── */
5
+ .tooltip-bubble {
6
+ background: var(--surface-100);
7
+ color: var(--text-color);
8
+ border: 1px solid var(--surface-border);
9
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
10
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import './Tooltip.css';
3
+ export type TooltipPosition = 'top' | 'right' | 'bottom' | 'left';
4
+ export interface TooltipProps {
5
+ content: string;
6
+ position?: TooltipPosition;
7
+ children: React.ReactNode;
8
+ }
9
+ export declare const Tooltip: React.FC<TooltipProps>;
10
+ //# sourceMappingURL=Tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../Common/Tooltip.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,eAAe,CAAC;AAGvB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAGlE,MAAM,WAAW,YAAY;IAEzB,OAAO,EAAE,MAAM,CAAC;IAEhB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAE3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAaD,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAa1C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import './Tooltip.css';
3
+
4
+ const POSITION_CLASSES = {
5
+ right: 'left-full ml-2 top-1/2 -translate-y-1/2',
6
+ left: 'right-full mr-2 top-1/2 -translate-y-1/2',
7
+ top: 'bottom-full mb-2 left-1/2 -translate-x-1/2',
8
+ bottom: 'top-full mt-2 left-1/2 -translate-x-1/2',
9
+ };
10
+ const Tooltip = ({ content, position = 'top', children }) => (jsxs("div", { className: 'relative group inline-flex', children: [children, jsx("div", { role: 'tooltip', className: `tooltip-bubble pointer-events-none absolute ${POSITION_CLASSES[position]} z-50
11
+ text-xs px-2 py-1 rounded
12
+ whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-150 delay-200`, style: { fontFamily: 'system-ui, sans-serif' }, children: content })] }));
13
+
14
+ export { Tooltip };
15
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../Common/Tooltip.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 from 'react';\nimport './Tooltip.css';\n\n/** Position of the tooltip relative to its trigger element. */\nexport type TooltipPosition = 'top' | 'right' | 'bottom' | 'left';\n\n/** Props for the {@link Tooltip} component. */\nexport interface TooltipProps {\n /** The text to display inside the tooltip. */\n content: string;\n /** Where the tooltip appears relative to the trigger (default: 'top'). */\n position?: TooltipPosition;\n /** The element that triggers the tooltip on hover. */\n children: React.ReactNode;\n}\n\nconst POSITION_CLASSES: Record<TooltipPosition, string> = {\n right: 'left-full ml-2 top-1/2 -translate-y-1/2',\n left: 'right-full mr-2 top-1/2 -translate-y-1/2',\n top: 'bottom-full mb-2 left-1/2 -translate-x-1/2',\n bottom: 'top-full mt-2 left-1/2 -translate-x-1/2',\n};\n\n/**\n * A CSS-only hover tooltip wrapper. Wraps any child element and displays\n * a styled floating label on hover without relying on native browser tooltips.\n */\nexport const Tooltip: React.FC<TooltipProps> = ({ content, position = 'top', children }) => (\n <div className='relative group inline-flex'>\n {children}\n <div\n role='tooltip'\n className={`tooltip-bubble pointer-events-none absolute ${POSITION_CLASSES[position]} z-50\n text-xs px-2 py-1 rounded\n whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-150 delay-200`}\n style={{ fontFamily: 'system-ui, sans-serif' }}\n >\n {content}\n </div>\n </div>\n);\n"],"names":["_jsxs","_jsx"],"mappings":";;;AAmBA,MAAM,gBAAgB,GAAoC;AACtD,IAAA,KAAK,EAAG,yCAAyC;AACjD,IAAA,IAAI,EAAI,0CAA0C;AAClD,IAAA,GAAG,EAAK,4CAA4C;AACpD,IAAA,MAAM,EAAE,yCAAyC;CACpD;AAMM,MAAM,OAAO,GAA2B,CAAC,EAAE,OAAO,EAAE,QAAQ,GAAG,KAAK,EAAE,QAAQ,EAAE,MACnFA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,4BAA4B,EAAA,QAAA,EAAA,CACtC,QAAQ,EACTC,aACI,IAAI,EAAC,SAAS,EACd,SAAS,EAAE,CAAA,4CAAA,EAA+C,gBAAgB,CAAC,QAAQ,CAAC,CAAA;;AAEc,6GAAA,CAAA,EAClG,KAAK,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE,EAAA,QAAA,EAE7C,OAAO,EAAA,CACN,CAAA,EAAA,CACJ;;;;"}
@@ -1,4 +1,5 @@
1
1
  export * from './ErrorBoundary';
2
2
  export * from './Page';
3
3
  export * from './FormElement';
4
+ export * from './Tooltip';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../Common/index.ts"],"names":[],"mappings":"AAGA,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../Common/index.ts"],"names":[],"mappings":"AAGA,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export { ErrorBoundary } from './ErrorBoundary.js';
2
2
  export { Page } from './Page.js';
3
3
  export { FormElement } from './FormElement.js';
4
+ export { Tooltip } from './Tooltip.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -0,0 +1,131 @@
1
+ /* Copyright (c) Cratis. All rights reserved. */
2
+ /* Licensed under the MIT license. See LICENSE file in the project root for full license information. */
3
+
4
+ /* ── Toolbar container ───────────────────────────────────────────────────── */
5
+ .toolbar {
6
+ background: var(--surface-card);
7
+ border: 1px solid var(--surface-border);
8
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
9
+ }
10
+
11
+ /* ── Toolbar button ──────────────────────────────────────────────────────── */
12
+ .toolbar-button {
13
+ color: var(--text-color-secondary);
14
+ background: transparent;
15
+ border: none;
16
+ transition: background 0.15s, color 0.15s;
17
+ }
18
+
19
+ .toolbar-button:hover {
20
+ background: var(--surface-100);
21
+ color: var(--text-color);
22
+ }
23
+
24
+ .toolbar-button--active {
25
+ background: var(--primary-color);
26
+ color: var(--primary-color-text);
27
+ }
28
+
29
+ .toolbar-button--active:hover {
30
+ background: var(--primary-color);
31
+ color: var(--primary-color-text);
32
+ }
33
+
34
+ /* ── Toolbar project name label ──────────────────────────────────────────── */
35
+ .toolbar-project-name {
36
+ padding: 0 8px;
37
+ font-size: 0.875rem;
38
+ font-weight: 500;
39
+ color: var(--text-color);
40
+ white-space: nowrap;
41
+ }
42
+
43
+ /* ── Toolbar section (context switching) ────────────────────────────────── */
44
+
45
+ /*
46
+ * The section is a fixed-size container that transitions smoothly between
47
+ * the dimensions required by each context.
48
+ * overflow is intentionally left as visible so that absolutely-positioned
49
+ * children (e.g. fan-out panels) can extend beyond the section's bounds.
50
+ * Inactive contexts are hidden via opacity/pointer-events, not overflow clipping.
51
+ */
52
+ .toolbar-section {
53
+ position: relative;
54
+ transition:
55
+ width 0.35s cubic-bezier(0.4, 0, 0.2, 1),
56
+ height 0.35s cubic-bezier(0.4, 0, 0.2, 1);
57
+ }
58
+
59
+ /*
60
+ * Every context is absolutely stacked at the top-left of the section.
61
+ * Only the active one is visible; the others fade out and lose pointer events.
62
+ */
63
+ .toolbar-context {
64
+ position: absolute;
65
+ top: 0;
66
+ left: 0;
67
+ transition: opacity 0.2s ease;
68
+ }
69
+
70
+ .toolbar-context--active {
71
+ opacity: 1;
72
+ pointer-events: auto;
73
+ }
74
+
75
+ .toolbar-context--inactive {
76
+ opacity: 0;
77
+ pointer-events: none;
78
+ }
79
+
80
+ /* ── Toolbar fan-out item ────────────────────────────────────────────────── */
81
+
82
+ /*
83
+ * The wrapper provides the positioning context for the absolutely-placed panel.
84
+ */
85
+ .toolbar-fanout-item {
86
+ position: relative;
87
+ }
88
+
89
+ /*
90
+ * The fan-out panel is a floating pill that mirrors the Toolbar container style.
91
+ * When collapsed, it's hidden. When expanded, it appears elevated at the same
92
+ * position as the trigger button, with the trigger button as the first item.
93
+ * Vertically centered with where the collapsed button would be.
94
+ */
95
+ .toolbar-fanout-panel {
96
+ position: absolute;
97
+ top: 50%;
98
+ left: calc(-0.5rem - 1px);
99
+ transform: translateY(-50%);
100
+ display: inline-flex;
101
+ flex-direction: row;
102
+ align-items: center;
103
+ gap: 0.25rem;
104
+ padding: 0.5rem;
105
+ background: var(--surface-card);
106
+ border: 1px solid var(--surface-border);
107
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
108
+ border-radius: 1rem;
109
+ white-space: nowrap;
110
+ z-index: 10;
111
+ pointer-events: none;
112
+ opacity: 0;
113
+ clip-path: inset(0 100% 0 0 round 1rem);
114
+ transition:
115
+ clip-path 0.35s cubic-bezier(0.4, 0, 0.2, 1),
116
+ opacity 0.2s ease;
117
+ }
118
+
119
+ /* Panel fans out to the left — reveal animates right → left */
120
+ .toolbar-fanout-panel--left {
121
+ left: auto;
122
+ right: calc(-0.5rem - 1px);
123
+ clip-path: inset(0 0 0 100% round 1rem);
124
+ }
125
+
126
+ /* Expanded state — fully visible, pointer events restored */
127
+ .toolbar-fanout-panel--visible {
128
+ clip-path: inset(0 0 0 0 round 1rem);
129
+ opacity: 1;
130
+ pointer-events: auto;
131
+ }
@@ -0,0 +1,8 @@
1
+ import { ReactNode } from 'react';
2
+ import './Toolbar.css';
3
+ export interface ToolbarProps {
4
+ children: ReactNode;
5
+ orientation?: 'vertical' | 'horizontal';
6
+ }
7
+ export declare const Toolbar: ({ children, orientation }: ToolbarProps) => import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=Toolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../Toolbar/Toolbar.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,eAAe,CAAC;AAGvB,MAAM,WAAW,YAAY;IAEzB,QAAQ,EAAE,SAAS,CAAC;IAEpB,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;CAC3C;AAOD,eAAO,MAAM,OAAO,GAAI,2BAAwC,YAAY,4CAQ3E,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import './Toolbar.css';
3
+
4
+ const Toolbar = ({ children, orientation = 'vertical' }) => (jsx("div", { className: `toolbar inline-flex ${orientation === 'horizontal' ? 'flex-row' : 'flex-col'} items-center gap-1 p-2 rounded-2xl`, children: children }));
5
+
6
+ export { Toolbar };
7
+ //# sourceMappingURL=Toolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolbar.js","sources":["../../../Toolbar/Toolbar.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 { ReactNode } from 'react';\nimport './Toolbar.css';\n\n/** Props for the {@link Toolbar} component. */\nexport interface ToolbarProps {\n /** The {@link ToolbarButton} elements to render inside this toolbar group. */\n children: ReactNode;\n /** Layout direction of the toolbar (default: 'vertical'). */\n orientation?: 'vertical' | 'horizontal';\n}\n\n/**\n * A toolbar container that groups icon buttons with a rounded border,\n * mimicking the style of tools panels found in canvas-based applications.\n * Supports both vertical (default) and horizontal orientations.\n */\nexport const Toolbar = ({ children, orientation = 'vertical' }: ToolbarProps) => (\n <div\n className={`toolbar inline-flex ${\n orientation === 'horizontal' ? 'flex-row' : 'flex-col'\n } items-center gap-1 p-2 rounded-2xl`}\n >\n {children}\n </div>\n);\n"],"names":["_jsx"],"mappings":";;;AAmBO,MAAM,OAAO,GAAG,CAAC,EAAE,QAAQ,EAAE,WAAW,GAAG,UAAU,EAAgB,MACxEA,GAAA,CAAA,KAAA,EAAA,EACI,SAAS,EAAE,CAAA,oBAAA,EACP,WAAW,KAAK,YAAY,GAAG,UAAU,GAAG,UAChD,CAAA,mCAAA,CAAqC,EAAA,QAAA,EAEpC,QAAQ,EAAA,CACP;;;;"}
@@ -0,0 +1,11 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Toolbar } from './Toolbar';
3
+ declare const meta: Meta<typeof Toolbar>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Toolbar>;
6
+ export declare const Default: Story;
7
+ export declare const MultipleGroups: Story;
8
+ export declare const WithActiveButton: Story;
9
+ export declare const WithContexts: Story;
10
+ export declare const WithFanOut: Story;
11
+ //# sourceMappingURL=Toolbar.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolbar.stories.d.ts","sourceRoot":"","sources":["../../../Toolbar/Toolbar.stories.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,OAAO,CAM9B,CAAC;AAEF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,OAAO,CAAC,CAAC;AAGtC,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,KAgB5B,CAAC;AAGF,eAAO,MAAM,gBAAgB,EAAE,KAqC9B,CAAC;AASF,eAAO,MAAM,YAAY,EAAE,KAoD1B,CAAC;AAQF,eAAO,MAAM,UAAU,EAAE,KA+CxB,CAAC"}