@almadar/ui 4.26.0 → 4.28.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/dist/avl/index.cjs +77 -7
- package/dist/avl/index.js +77 -7
- package/dist/components/index.cjs +28 -0
- package/dist/components/index.js +28 -0
- package/dist/components/templates/DashboardLayout.d.ts +26 -1
- package/dist/providers/index.cjs +28 -0
- package/dist/providers/index.js +28 -0
- package/dist/runtime/index.cjs +28 -0
- package/dist/runtime/index.js +28 -0
- package/package.json +2 -2
package/dist/avl/index.cjs
CHANGED
|
@@ -41,6 +41,7 @@ var postprocessing = require('@react-three/postprocessing');
|
|
|
41
41
|
var patterns = require('@almadar/patterns');
|
|
42
42
|
var ELK = require('elkjs/lib/elk.bundled.js');
|
|
43
43
|
var react = require('@xyflow/react');
|
|
44
|
+
var OrbitalServerRuntime = require('@almadar/runtime/OrbitalServerRuntime');
|
|
44
45
|
var runtime = require('@almadar/runtime');
|
|
45
46
|
|
|
46
47
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -10212,13 +10213,13 @@ var init_MapView = __esm({
|
|
|
10212
10213
|
shadowSize: [41, 41]
|
|
10213
10214
|
});
|
|
10214
10215
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
10215
|
-
const { useEffect:
|
|
10216
|
+
const { useEffect: useEffect81, useRef: useRef81, useCallback: useCallback105, useState: useState107 } = React118__namespace.default;
|
|
10216
10217
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
10217
10218
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
10218
10219
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
10219
10220
|
const map = useMap();
|
|
10220
10221
|
const prevRef = useRef81({ centerLat, centerLng, zoom });
|
|
10221
|
-
|
|
10222
|
+
useEffect81(() => {
|
|
10222
10223
|
const prev = prevRef.current;
|
|
10223
10224
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
10224
10225
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -10229,7 +10230,7 @@ var init_MapView = __esm({
|
|
|
10229
10230
|
}
|
|
10230
10231
|
function MapClickHandler({ onMapClick }) {
|
|
10231
10232
|
const map = useMap();
|
|
10232
|
-
|
|
10233
|
+
useEffect81(() => {
|
|
10233
10234
|
if (!onMapClick) return;
|
|
10234
10235
|
const handler = (e) => {
|
|
10235
10236
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -10256,7 +10257,7 @@ var init_MapView = __esm({
|
|
|
10256
10257
|
showAttribution = true
|
|
10257
10258
|
}) {
|
|
10258
10259
|
const eventBus = useEventBus3();
|
|
10259
|
-
const [clickedPosition, setClickedPosition] =
|
|
10260
|
+
const [clickedPosition, setClickedPosition] = useState107(null);
|
|
10260
10261
|
const handleMapClick = useCallback105((lat, lng) => {
|
|
10261
10262
|
if (showClickedPin) {
|
|
10262
10263
|
setClickedPosition({ lat, lng });
|
|
@@ -20636,6 +20637,7 @@ var init_DashboardLayout = __esm({
|
|
|
20636
20637
|
showSearch = false,
|
|
20637
20638
|
searchEvent,
|
|
20638
20639
|
onSearchSubmit,
|
|
20640
|
+
topBarActions = [],
|
|
20639
20641
|
notifications,
|
|
20640
20642
|
notificationClickEvent,
|
|
20641
20643
|
onNotificationClick,
|
|
@@ -20656,6 +20658,9 @@ var init_DashboardLayout = __esm({
|
|
|
20656
20658
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
20657
20659
|
if (onNotificationClick) onNotificationClick();
|
|
20658
20660
|
};
|
|
20661
|
+
const handleTopBarActionClick = (event) => {
|
|
20662
|
+
eventBus.emit(`UI:${event}`, {});
|
|
20663
|
+
};
|
|
20659
20664
|
const [sidebarOpen, setSidebarOpen] = React118.useState(false);
|
|
20660
20665
|
const [userMenuOpen, setUserMenuOpen] = React118.useState(false);
|
|
20661
20666
|
const location = reactRouterDom.useLocation();
|
|
@@ -20782,6 +20787,30 @@ var init_DashboardLayout = __esm({
|
|
|
20782
20787
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
20783
20788
|
headerActions,
|
|
20784
20789
|
showThemeToggle && /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, {}),
|
|
20790
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
20791
|
+
Button,
|
|
20792
|
+
{
|
|
20793
|
+
variant: "ghost",
|
|
20794
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
20795
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
20796
|
+
"aria-label": action.label ?? action.icon,
|
|
20797
|
+
children: [
|
|
20798
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
20799
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
20800
|
+
Box,
|
|
20801
|
+
{
|
|
20802
|
+
as: "span",
|
|
20803
|
+
className: cn(
|
|
20804
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
20805
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
20806
|
+
),
|
|
20807
|
+
children: action.badge
|
|
20808
|
+
}
|
|
20809
|
+
)
|
|
20810
|
+
]
|
|
20811
|
+
},
|
|
20812
|
+
`${action.event}-${idx}`
|
|
20813
|
+
)),
|
|
20785
20814
|
notificationsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
20786
20815
|
Button,
|
|
20787
20816
|
{
|
|
@@ -50322,6 +50351,48 @@ function OrbPreview({
|
|
|
50322
50351
|
);
|
|
50323
50352
|
}
|
|
50324
50353
|
OrbPreview.displayName = "OrbPreview";
|
|
50354
|
+
function BrowserPlayground({
|
|
50355
|
+
schema,
|
|
50356
|
+
mode = "mock",
|
|
50357
|
+
initialPagePath,
|
|
50358
|
+
height,
|
|
50359
|
+
className
|
|
50360
|
+
}) {
|
|
50361
|
+
const [runtime] = React118.useState(
|
|
50362
|
+
() => new OrbitalServerRuntime.OrbitalServerRuntime({ mode, debug: false })
|
|
50363
|
+
);
|
|
50364
|
+
React118.useEffect(() => {
|
|
50365
|
+
void runtime.register(schema);
|
|
50366
|
+
return () => {
|
|
50367
|
+
runtime.unregisterAll();
|
|
50368
|
+
};
|
|
50369
|
+
}, [runtime, schema]);
|
|
50370
|
+
const transport = React118.useMemo(() => ({
|
|
50371
|
+
register: async (s) => {
|
|
50372
|
+
await runtime.register(s);
|
|
50373
|
+
return true;
|
|
50374
|
+
},
|
|
50375
|
+
unregister: async () => {
|
|
50376
|
+
runtime.unregisterAll();
|
|
50377
|
+
},
|
|
50378
|
+
sendEvent: async (orbitalName, event, payload) => {
|
|
50379
|
+
return runtime.processOrbitalEvent(orbitalName, {
|
|
50380
|
+
event,
|
|
50381
|
+
payload
|
|
50382
|
+
});
|
|
50383
|
+
}
|
|
50384
|
+
}), [runtime]);
|
|
50385
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
50386
|
+
OrbPreview,
|
|
50387
|
+
{
|
|
50388
|
+
schema,
|
|
50389
|
+
transport,
|
|
50390
|
+
initialPagePath,
|
|
50391
|
+
height,
|
|
50392
|
+
className
|
|
50393
|
+
}
|
|
50394
|
+
);
|
|
50395
|
+
}
|
|
50325
50396
|
|
|
50326
50397
|
// components/molecules/avl/OrbPreviewNode.tsx
|
|
50327
50398
|
init_useEventBus();
|
|
@@ -50502,7 +50573,6 @@ var OrbPreviewNodeInner = (props) => {
|
|
|
50502
50573
|
}
|
|
50503
50574
|
return buildOrbitalSchema(fullSchema, data.orbitalName);
|
|
50504
50575
|
}, [data._fullSchema, data.orbitalName, data.traitName, data.transitionEvent, data.fromState, data.toState, isExpanded]);
|
|
50505
|
-
const mockData = data._mockData ?? void 0;
|
|
50506
50576
|
const handleContentClick = React118.useCallback((e) => {
|
|
50507
50577
|
e.stopPropagation();
|
|
50508
50578
|
const target = e.target;
|
|
@@ -50676,10 +50746,10 @@ var OrbPreviewNodeInner = (props) => {
|
|
|
50676
50746
|
onDragOver: handlePreviewDragOver,
|
|
50677
50747
|
onDragLeave: handlePreviewDragLeave,
|
|
50678
50748
|
children: orbitalSchema ? /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
50679
|
-
|
|
50749
|
+
BrowserPlayground,
|
|
50680
50750
|
{
|
|
50681
50751
|
schema: orbitalSchema,
|
|
50682
|
-
|
|
50752
|
+
mode: "mock",
|
|
50683
50753
|
height: "auto"
|
|
50684
50754
|
}
|
|
50685
50755
|
) }) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex items-center justify-center", style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground", children: "No preview available" }) })
|
package/dist/avl/index.js
CHANGED
|
@@ -42,6 +42,7 @@ import { EffectComposer, Bloom, DepthOfField, Vignette } from '@react-three/post
|
|
|
42
42
|
import { getPatternDefinition, getComponentForPattern as getComponentForPattern$1, isEntityAwarePattern } from '@almadar/patterns';
|
|
43
43
|
import ELK from 'elkjs/lib/elk.bundled.js';
|
|
44
44
|
import { MarkerType, Handle, Position, getBezierPath, EdgeLabelRenderer, BaseEdge, ReactFlowProvider, useNodesState, useEdgesState, useReactFlow, ReactFlow, Controls, Background, BackgroundVariant } from '@xyflow/react';
|
|
45
|
+
import { OrbitalServerRuntime } from '@almadar/runtime/OrbitalServerRuntime';
|
|
45
46
|
import { InMemoryPersistence, StateMachineManager, createContextFromBindings, interpolateValue, collectDeclaredConfigDefaults, createServerEffectHandlers, EffectExecutor } from '@almadar/runtime';
|
|
46
47
|
|
|
47
48
|
var __defProp = Object.defineProperty;
|
|
@@ -10166,13 +10167,13 @@ var init_MapView = __esm({
|
|
|
10166
10167
|
shadowSize: [41, 41]
|
|
10167
10168
|
});
|
|
10168
10169
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
10169
|
-
const { useEffect:
|
|
10170
|
+
const { useEffect: useEffect81, useRef: useRef81, useCallback: useCallback105, useState: useState107 } = React118__default;
|
|
10170
10171
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
10171
10172
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
10172
10173
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
10173
10174
|
const map = useMap();
|
|
10174
10175
|
const prevRef = useRef81({ centerLat, centerLng, zoom });
|
|
10175
|
-
|
|
10176
|
+
useEffect81(() => {
|
|
10176
10177
|
const prev = prevRef.current;
|
|
10177
10178
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
10178
10179
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -10183,7 +10184,7 @@ var init_MapView = __esm({
|
|
|
10183
10184
|
}
|
|
10184
10185
|
function MapClickHandler({ onMapClick }) {
|
|
10185
10186
|
const map = useMap();
|
|
10186
|
-
|
|
10187
|
+
useEffect81(() => {
|
|
10187
10188
|
if (!onMapClick) return;
|
|
10188
10189
|
const handler = (e) => {
|
|
10189
10190
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -10210,7 +10211,7 @@ var init_MapView = __esm({
|
|
|
10210
10211
|
showAttribution = true
|
|
10211
10212
|
}) {
|
|
10212
10213
|
const eventBus = useEventBus3();
|
|
10213
|
-
const [clickedPosition, setClickedPosition] =
|
|
10214
|
+
const [clickedPosition, setClickedPosition] = useState107(null);
|
|
10214
10215
|
const handleMapClick = useCallback105((lat, lng) => {
|
|
10215
10216
|
if (showClickedPin) {
|
|
10216
10217
|
setClickedPosition({ lat, lng });
|
|
@@ -20590,6 +20591,7 @@ var init_DashboardLayout = __esm({
|
|
|
20590
20591
|
showSearch = false,
|
|
20591
20592
|
searchEvent,
|
|
20592
20593
|
onSearchSubmit,
|
|
20594
|
+
topBarActions = [],
|
|
20593
20595
|
notifications,
|
|
20594
20596
|
notificationClickEvent,
|
|
20595
20597
|
onNotificationClick,
|
|
@@ -20610,6 +20612,9 @@ var init_DashboardLayout = __esm({
|
|
|
20610
20612
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
20611
20613
|
if (onNotificationClick) onNotificationClick();
|
|
20612
20614
|
};
|
|
20615
|
+
const handleTopBarActionClick = (event) => {
|
|
20616
|
+
eventBus.emit(`UI:${event}`, {});
|
|
20617
|
+
};
|
|
20613
20618
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
20614
20619
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
|
20615
20620
|
const location = useLocation();
|
|
@@ -20736,6 +20741,30 @@ var init_DashboardLayout = __esm({
|
|
|
20736
20741
|
/* @__PURE__ */ jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
20737
20742
|
headerActions,
|
|
20738
20743
|
showThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}),
|
|
20744
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
20745
|
+
Button,
|
|
20746
|
+
{
|
|
20747
|
+
variant: "ghost",
|
|
20748
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
20749
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
20750
|
+
"aria-label": action.label ?? action.icon,
|
|
20751
|
+
children: [
|
|
20752
|
+
/* @__PURE__ */ jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
20753
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsx(
|
|
20754
|
+
Box,
|
|
20755
|
+
{
|
|
20756
|
+
as: "span",
|
|
20757
|
+
className: cn(
|
|
20758
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
20759
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
20760
|
+
),
|
|
20761
|
+
children: action.badge
|
|
20762
|
+
}
|
|
20763
|
+
)
|
|
20764
|
+
]
|
|
20765
|
+
},
|
|
20766
|
+
`${action.event}-${idx}`
|
|
20767
|
+
)),
|
|
20739
20768
|
notificationsEnabled && /* @__PURE__ */ jsxs(
|
|
20740
20769
|
Button,
|
|
20741
20770
|
{
|
|
@@ -50276,6 +50305,48 @@ function OrbPreview({
|
|
|
50276
50305
|
);
|
|
50277
50306
|
}
|
|
50278
50307
|
OrbPreview.displayName = "OrbPreview";
|
|
50308
|
+
function BrowserPlayground({
|
|
50309
|
+
schema,
|
|
50310
|
+
mode = "mock",
|
|
50311
|
+
initialPagePath,
|
|
50312
|
+
height,
|
|
50313
|
+
className
|
|
50314
|
+
}) {
|
|
50315
|
+
const [runtime] = useState(
|
|
50316
|
+
() => new OrbitalServerRuntime({ mode, debug: false })
|
|
50317
|
+
);
|
|
50318
|
+
useEffect(() => {
|
|
50319
|
+
void runtime.register(schema);
|
|
50320
|
+
return () => {
|
|
50321
|
+
runtime.unregisterAll();
|
|
50322
|
+
};
|
|
50323
|
+
}, [runtime, schema]);
|
|
50324
|
+
const transport = useMemo(() => ({
|
|
50325
|
+
register: async (s) => {
|
|
50326
|
+
await runtime.register(s);
|
|
50327
|
+
return true;
|
|
50328
|
+
},
|
|
50329
|
+
unregister: async () => {
|
|
50330
|
+
runtime.unregisterAll();
|
|
50331
|
+
},
|
|
50332
|
+
sendEvent: async (orbitalName, event, payload) => {
|
|
50333
|
+
return runtime.processOrbitalEvent(orbitalName, {
|
|
50334
|
+
event,
|
|
50335
|
+
payload
|
|
50336
|
+
});
|
|
50337
|
+
}
|
|
50338
|
+
}), [runtime]);
|
|
50339
|
+
return /* @__PURE__ */ jsx(
|
|
50340
|
+
OrbPreview,
|
|
50341
|
+
{
|
|
50342
|
+
schema,
|
|
50343
|
+
transport,
|
|
50344
|
+
initialPagePath,
|
|
50345
|
+
height,
|
|
50346
|
+
className
|
|
50347
|
+
}
|
|
50348
|
+
);
|
|
50349
|
+
}
|
|
50279
50350
|
|
|
50280
50351
|
// components/molecules/avl/OrbPreviewNode.tsx
|
|
50281
50352
|
init_useEventBus();
|
|
@@ -50456,7 +50527,6 @@ var OrbPreviewNodeInner = (props) => {
|
|
|
50456
50527
|
}
|
|
50457
50528
|
return buildOrbitalSchema(fullSchema, data.orbitalName);
|
|
50458
50529
|
}, [data._fullSchema, data.orbitalName, data.traitName, data.transitionEvent, data.fromState, data.toState, isExpanded]);
|
|
50459
|
-
const mockData = data._mockData ?? void 0;
|
|
50460
50530
|
const handleContentClick = useCallback((e) => {
|
|
50461
50531
|
e.stopPropagation();
|
|
50462
50532
|
const target = e.target;
|
|
@@ -50630,10 +50700,10 @@ var OrbPreviewNodeInner = (props) => {
|
|
|
50630
50700
|
onDragOver: handlePreviewDragOver,
|
|
50631
50701
|
onDragLeave: handlePreviewDragLeave,
|
|
50632
50702
|
children: orbitalSchema ? /* @__PURE__ */ jsx(Box, { style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsx(
|
|
50633
|
-
|
|
50703
|
+
BrowserPlayground,
|
|
50634
50704
|
{
|
|
50635
50705
|
schema: orbitalSchema,
|
|
50636
|
-
|
|
50706
|
+
mode: "mock",
|
|
50637
50707
|
height: "auto"
|
|
50638
50708
|
}
|
|
50639
50709
|
) }) : /* @__PURE__ */ jsx(Box, { className: "flex items-center justify-center", style: { minHeight: preset.minHeight }, children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground", children: "No preview available" }) })
|
|
@@ -17000,6 +17000,7 @@ var init_DashboardLayout = __esm({
|
|
|
17000
17000
|
showSearch = false,
|
|
17001
17001
|
searchEvent,
|
|
17002
17002
|
onSearchSubmit,
|
|
17003
|
+
topBarActions = [],
|
|
17003
17004
|
notifications,
|
|
17004
17005
|
notificationClickEvent,
|
|
17005
17006
|
onNotificationClick,
|
|
@@ -17020,6 +17021,9 @@ var init_DashboardLayout = __esm({
|
|
|
17020
17021
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
17021
17022
|
if (onNotificationClick) onNotificationClick();
|
|
17022
17023
|
};
|
|
17024
|
+
const handleTopBarActionClick = (event) => {
|
|
17025
|
+
eventBus.emit(`UI:${event}`, {});
|
|
17026
|
+
};
|
|
17023
17027
|
const [sidebarOpen, setSidebarOpen] = React109.useState(false);
|
|
17024
17028
|
const [userMenuOpen, setUserMenuOpen] = React109.useState(false);
|
|
17025
17029
|
const location = reactRouterDom.useLocation();
|
|
@@ -17150,6 +17154,30 @@ var init_DashboardLayout = __esm({
|
|
|
17150
17154
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { align: "center", gap: "xs", children: [
|
|
17151
17155
|
headerActions,
|
|
17152
17156
|
showThemeToggle && /* @__PURE__ */ jsxRuntime.jsx(exports.ThemeToggle, {}),
|
|
17157
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17158
|
+
exports.Button,
|
|
17159
|
+
{
|
|
17160
|
+
variant: "ghost",
|
|
17161
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
17162
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
17163
|
+
"aria-label": action.label ?? action.icon,
|
|
17164
|
+
children: [
|
|
17165
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
17166
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17167
|
+
exports.Box,
|
|
17168
|
+
{
|
|
17169
|
+
as: "span",
|
|
17170
|
+
className: cn(
|
|
17171
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
17172
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
17173
|
+
),
|
|
17174
|
+
children: action.badge
|
|
17175
|
+
}
|
|
17176
|
+
)
|
|
17177
|
+
]
|
|
17178
|
+
},
|
|
17179
|
+
`${action.event}-${idx}`
|
|
17180
|
+
)),
|
|
17153
17181
|
notificationsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17154
17182
|
exports.Button,
|
|
17155
17183
|
{
|
package/dist/components/index.js
CHANGED
|
@@ -16955,6 +16955,7 @@ var init_DashboardLayout = __esm({
|
|
|
16955
16955
|
showSearch = false,
|
|
16956
16956
|
searchEvent,
|
|
16957
16957
|
onSearchSubmit,
|
|
16958
|
+
topBarActions = [],
|
|
16958
16959
|
notifications,
|
|
16959
16960
|
notificationClickEvent,
|
|
16960
16961
|
onNotificationClick,
|
|
@@ -16975,6 +16976,9 @@ var init_DashboardLayout = __esm({
|
|
|
16975
16976
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
16976
16977
|
if (onNotificationClick) onNotificationClick();
|
|
16977
16978
|
};
|
|
16979
|
+
const handleTopBarActionClick = (event) => {
|
|
16980
|
+
eventBus.emit(`UI:${event}`, {});
|
|
16981
|
+
};
|
|
16978
16982
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
16979
16983
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
|
16980
16984
|
const location = useLocation();
|
|
@@ -17105,6 +17109,30 @@ var init_DashboardLayout = __esm({
|
|
|
17105
17109
|
/* @__PURE__ */ jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
17106
17110
|
headerActions,
|
|
17107
17111
|
showThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}),
|
|
17112
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
17113
|
+
Button,
|
|
17114
|
+
{
|
|
17115
|
+
variant: "ghost",
|
|
17116
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
17117
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
17118
|
+
"aria-label": action.label ?? action.icon,
|
|
17119
|
+
children: [
|
|
17120
|
+
/* @__PURE__ */ jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
17121
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsx(
|
|
17122
|
+
Box,
|
|
17123
|
+
{
|
|
17124
|
+
as: "span",
|
|
17125
|
+
className: cn(
|
|
17126
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
17127
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
17128
|
+
),
|
|
17129
|
+
children: action.badge
|
|
17130
|
+
}
|
|
17131
|
+
)
|
|
17132
|
+
]
|
|
17133
|
+
},
|
|
17134
|
+
`${action.event}-${idx}`
|
|
17135
|
+
)),
|
|
17108
17136
|
notificationsEnabled && /* @__PURE__ */ jsxs(
|
|
17109
17137
|
Button,
|
|
17110
17138
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { LucideIcon } from "lucide-react";
|
|
3
|
-
import type { EventEmit } from "@almadar/core";
|
|
3
|
+
import type { EventEmit, EventKey } from "@almadar/core";
|
|
4
4
|
export interface NavItem {
|
|
5
5
|
label: string;
|
|
6
6
|
href: string;
|
|
@@ -20,6 +20,25 @@ export interface NotificationItem {
|
|
|
20
20
|
/** Optional flag — bell badge counts items where read !== true. */
|
|
21
21
|
read?: boolean;
|
|
22
22
|
}
|
|
23
|
+
/** A generic top-bar action button. Domain-agnostic — consumers wire any
|
|
24
|
+
* combination (cart icon, profile, help, custom). Each entry renders as
|
|
25
|
+
* an icon button between the search bar and the notifications bell;
|
|
26
|
+
* click dispatches the configured event onto the bus. */
|
|
27
|
+
export interface TopBarAction {
|
|
28
|
+
/** Lucide icon name (e.g. "shopping-cart", "user", "help-circle"). */
|
|
29
|
+
icon: string;
|
|
30
|
+
/** Optional aria-label / tooltip. Falls back to `icon`. */
|
|
31
|
+
label?: string;
|
|
32
|
+
/** Bus event fired on click. Dispatched as `UI:{event}` with empty payload.
|
|
33
|
+
* Typed as `EventKey` so the pattern-sync detector marks `topBarActions`
|
|
34
|
+
* as `event-list` and the validator checks references against trait
|
|
35
|
+
* emit/listen sets. */
|
|
36
|
+
event: EventKey;
|
|
37
|
+
/** Optional badge — number or string rendered in the corner of the icon. */
|
|
38
|
+
badge?: number | string;
|
|
39
|
+
/** Visual variant. Default `"default"`. */
|
|
40
|
+
variant?: "default" | "primary" | "danger";
|
|
41
|
+
}
|
|
23
42
|
export interface DashboardLayoutProps {
|
|
24
43
|
/** App name shown in sidebar */
|
|
25
44
|
appName?: string;
|
|
@@ -49,6 +68,12 @@ export interface DashboardLayoutProps {
|
|
|
49
68
|
/** React-side search submit callback. Used when the host wires the
|
|
50
69
|
* layout directly (not via render-ui pattern resolution). */
|
|
51
70
|
onSearchSubmit?: (value: string) => void;
|
|
71
|
+
/** Generic top-bar action buttons rendered between the search bar and
|
|
72
|
+
* the notifications bell. Each entry: `{icon, label?, event, badge?, variant?}`.
|
|
73
|
+
* Domain-agnostic — consumers add a cart icon, profile button, help-bubble,
|
|
74
|
+
* or any other top-bar action by appending entries. Empty array (default)
|
|
75
|
+
* renders nothing. */
|
|
76
|
+
topBarActions?: TopBarAction[];
|
|
52
77
|
/** Notification list. Pass an empty array to show the bell with no
|
|
53
78
|
* badge; omit / pass null to hide the bell entirely. */
|
|
54
79
|
notifications?: NotificationItem[] | null;
|
package/dist/providers/index.cjs
CHANGED
|
@@ -17394,6 +17394,7 @@ var init_DashboardLayout = __esm({
|
|
|
17394
17394
|
showSearch = false,
|
|
17395
17395
|
searchEvent,
|
|
17396
17396
|
onSearchSubmit,
|
|
17397
|
+
topBarActions = [],
|
|
17397
17398
|
notifications,
|
|
17398
17399
|
notificationClickEvent,
|
|
17399
17400
|
onNotificationClick,
|
|
@@ -17414,6 +17415,9 @@ var init_DashboardLayout = __esm({
|
|
|
17414
17415
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
17415
17416
|
if (onNotificationClick) onNotificationClick();
|
|
17416
17417
|
};
|
|
17418
|
+
const handleTopBarActionClick = (event) => {
|
|
17419
|
+
eventBus.emit(`UI:${event}`, {});
|
|
17420
|
+
};
|
|
17417
17421
|
const [sidebarOpen, setSidebarOpen] = React105.useState(false);
|
|
17418
17422
|
const [userMenuOpen, setUserMenuOpen] = React105.useState(false);
|
|
17419
17423
|
const location = reactRouterDom.useLocation();
|
|
@@ -17540,6 +17544,30 @@ var init_DashboardLayout = __esm({
|
|
|
17540
17544
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
17541
17545
|
headerActions,
|
|
17542
17546
|
showThemeToggle && /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, {}),
|
|
17547
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17548
|
+
Button,
|
|
17549
|
+
{
|
|
17550
|
+
variant: "ghost",
|
|
17551
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
17552
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
17553
|
+
"aria-label": action.label ?? action.icon,
|
|
17554
|
+
children: [
|
|
17555
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
17556
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17557
|
+
Box,
|
|
17558
|
+
{
|
|
17559
|
+
as: "span",
|
|
17560
|
+
className: cn(
|
|
17561
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
17562
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
17563
|
+
),
|
|
17564
|
+
children: action.badge
|
|
17565
|
+
}
|
|
17566
|
+
)
|
|
17567
|
+
]
|
|
17568
|
+
},
|
|
17569
|
+
`${action.event}-${idx}`
|
|
17570
|
+
)),
|
|
17543
17571
|
notificationsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17544
17572
|
Button,
|
|
17545
17573
|
{
|
package/dist/providers/index.js
CHANGED
|
@@ -17349,6 +17349,7 @@ var init_DashboardLayout = __esm({
|
|
|
17349
17349
|
showSearch = false,
|
|
17350
17350
|
searchEvent,
|
|
17351
17351
|
onSearchSubmit,
|
|
17352
|
+
topBarActions = [],
|
|
17352
17353
|
notifications,
|
|
17353
17354
|
notificationClickEvent,
|
|
17354
17355
|
onNotificationClick,
|
|
@@ -17369,6 +17370,9 @@ var init_DashboardLayout = __esm({
|
|
|
17369
17370
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
17370
17371
|
if (onNotificationClick) onNotificationClick();
|
|
17371
17372
|
};
|
|
17373
|
+
const handleTopBarActionClick = (event) => {
|
|
17374
|
+
eventBus.emit(`UI:${event}`, {});
|
|
17375
|
+
};
|
|
17372
17376
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
17373
17377
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
|
17374
17378
|
const location = useLocation();
|
|
@@ -17495,6 +17499,30 @@ var init_DashboardLayout = __esm({
|
|
|
17495
17499
|
/* @__PURE__ */ jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
17496
17500
|
headerActions,
|
|
17497
17501
|
showThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}),
|
|
17502
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
17503
|
+
Button,
|
|
17504
|
+
{
|
|
17505
|
+
variant: "ghost",
|
|
17506
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
17507
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
17508
|
+
"aria-label": action.label ?? action.icon,
|
|
17509
|
+
children: [
|
|
17510
|
+
/* @__PURE__ */ jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
17511
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsx(
|
|
17512
|
+
Box,
|
|
17513
|
+
{
|
|
17514
|
+
as: "span",
|
|
17515
|
+
className: cn(
|
|
17516
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
17517
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
17518
|
+
),
|
|
17519
|
+
children: action.badge
|
|
17520
|
+
}
|
|
17521
|
+
)
|
|
17522
|
+
]
|
|
17523
|
+
},
|
|
17524
|
+
`${action.event}-${idx}`
|
|
17525
|
+
)),
|
|
17498
17526
|
notificationsEnabled && /* @__PURE__ */ jsxs(
|
|
17499
17527
|
Button,
|
|
17500
17528
|
{
|
package/dist/runtime/index.cjs
CHANGED
|
@@ -17163,6 +17163,7 @@ var init_DashboardLayout = __esm({
|
|
|
17163
17163
|
showSearch = false,
|
|
17164
17164
|
searchEvent,
|
|
17165
17165
|
onSearchSubmit,
|
|
17166
|
+
topBarActions = [],
|
|
17166
17167
|
notifications,
|
|
17167
17168
|
notificationClickEvent,
|
|
17168
17169
|
onNotificationClick,
|
|
@@ -17183,6 +17184,9 @@ var init_DashboardLayout = __esm({
|
|
|
17183
17184
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
17184
17185
|
if (onNotificationClick) onNotificationClick();
|
|
17185
17186
|
};
|
|
17187
|
+
const handleTopBarActionClick = (event) => {
|
|
17188
|
+
eventBus.emit(`UI:${event}`, {});
|
|
17189
|
+
};
|
|
17186
17190
|
const [sidebarOpen, setSidebarOpen] = React104.useState(false);
|
|
17187
17191
|
const [userMenuOpen, setUserMenuOpen] = React104.useState(false);
|
|
17188
17192
|
const location = reactRouterDom.useLocation();
|
|
@@ -17309,6 +17313,30 @@ var init_DashboardLayout = __esm({
|
|
|
17309
17313
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
17310
17314
|
headerActions,
|
|
17311
17315
|
showThemeToggle && /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, {}),
|
|
17316
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17317
|
+
Button,
|
|
17318
|
+
{
|
|
17319
|
+
variant: "ghost",
|
|
17320
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
17321
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
17322
|
+
"aria-label": action.label ?? action.icon,
|
|
17323
|
+
children: [
|
|
17324
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
17325
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17326
|
+
Box,
|
|
17327
|
+
{
|
|
17328
|
+
as: "span",
|
|
17329
|
+
className: cn(
|
|
17330
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
17331
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
17332
|
+
),
|
|
17333
|
+
children: action.badge
|
|
17334
|
+
}
|
|
17335
|
+
)
|
|
17336
|
+
]
|
|
17337
|
+
},
|
|
17338
|
+
`${action.event}-${idx}`
|
|
17339
|
+
)),
|
|
17312
17340
|
notificationsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17313
17341
|
Button,
|
|
17314
17342
|
{
|
package/dist/runtime/index.js
CHANGED
|
@@ -17118,6 +17118,7 @@ var init_DashboardLayout = __esm({
|
|
|
17118
17118
|
showSearch = false,
|
|
17119
17119
|
searchEvent,
|
|
17120
17120
|
onSearchSubmit,
|
|
17121
|
+
topBarActions = [],
|
|
17121
17122
|
notifications,
|
|
17122
17123
|
notificationClickEvent,
|
|
17123
17124
|
onNotificationClick,
|
|
@@ -17138,6 +17139,9 @@ var init_DashboardLayout = __esm({
|
|
|
17138
17139
|
if (notificationClickEvent) eventBus.emit(`UI:${notificationClickEvent}`, {});
|
|
17139
17140
|
if (onNotificationClick) onNotificationClick();
|
|
17140
17141
|
};
|
|
17142
|
+
const handleTopBarActionClick = (event) => {
|
|
17143
|
+
eventBus.emit(`UI:${event}`, {});
|
|
17144
|
+
};
|
|
17141
17145
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
|
17142
17146
|
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
|
17143
17147
|
const location = useLocation();
|
|
@@ -17264,6 +17268,30 @@ var init_DashboardLayout = __esm({
|
|
|
17264
17268
|
/* @__PURE__ */ jsxs(HStack, { align: "center", gap: "xs", children: [
|
|
17265
17269
|
headerActions,
|
|
17266
17270
|
showThemeToggle && /* @__PURE__ */ jsx(ThemeToggle, {}),
|
|
17271
|
+
topBarActions.map((action, idx) => /* @__PURE__ */ jsxs(
|
|
17272
|
+
Button,
|
|
17273
|
+
{
|
|
17274
|
+
variant: "ghost",
|
|
17275
|
+
className: "relative p-2 rounded-full hover:bg-muted dark:hover:bg-muted",
|
|
17276
|
+
onClick: () => handleTopBarActionClick(action.event),
|
|
17277
|
+
"aria-label": action.label ?? action.icon,
|
|
17278
|
+
children: [
|
|
17279
|
+
/* @__PURE__ */ jsx(Icon, { name: action.icon, className: "h-5 w-5 text-muted-foreground dark:text-muted-foreground" }),
|
|
17280
|
+
action.badge !== void 0 && action.badge !== null && action.badge !== 0 && action.badge !== "" && /* @__PURE__ */ jsx(
|
|
17281
|
+
Box,
|
|
17282
|
+
{
|
|
17283
|
+
as: "span",
|
|
17284
|
+
className: cn(
|
|
17285
|
+
"absolute -top-0.5 -right-0.5 min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-semibold text-white flex items-center justify-center",
|
|
17286
|
+
action.variant === "danger" ? "bg-error" : action.variant === "primary" ? "bg-primary" : "bg-foreground"
|
|
17287
|
+
),
|
|
17288
|
+
children: action.badge
|
|
17289
|
+
}
|
|
17290
|
+
)
|
|
17291
|
+
]
|
|
17292
|
+
},
|
|
17293
|
+
`${action.event}-${idx}`
|
|
17294
|
+
)),
|
|
17267
17295
|
notificationsEnabled && /* @__PURE__ */ jsxs(
|
|
17268
17296
|
Button,
|
|
17269
17297
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/ui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.28.0",
|
|
4
4
|
"description": "React UI components, hooks, and providers for Almadar",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"dependencies": {
|
|
125
125
|
"@almadar/core": ">=7.12.0",
|
|
126
126
|
"@almadar/evaluator": ">=2.9.2",
|
|
127
|
-
"@almadar/patterns": "^2.
|
|
127
|
+
"@almadar/patterns": "^2.21.0",
|
|
128
128
|
"@almadar/runtime": "^6.0.0",
|
|
129
129
|
"@almadar/std": ">=6.4.1",
|
|
130
130
|
"@almadar/syntax": ">=1.3.1",
|