@ensera/plugin-frontend 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
- # @ensera/plugin-frontend
2
-
3
- Frontend runtime SDK for Ensera plugins.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install @ensera/plugin-frontend
9
- ```
10
-
11
- ## Purpose
12
-
13
- - mounts frontend features inside Ensera Core
14
- - provides the runtime APIs used by the published templates
15
- - stays separate from the scaffold template packages
1
+ # @ensera/plugin-frontend
2
+
3
+ Frontend runtime SDK for Ensera plugins.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @ensera/plugin-frontend
9
+ ```
10
+
11
+ ## Purpose
12
+
13
+ - mounts frontend features inside Ensera Core
14
+ - provides the runtime APIs used by the published templates
15
+ - stays separate from the scaffold template packages
package/dist/index.d.ts CHANGED
@@ -71,6 +71,23 @@ type PluginCtx = {
71
71
  * Backward compatible: older Core can omit.
72
72
  */
73
73
  launch?: PluginLaunch;
74
+ /**
75
+ * Optional: current Core theme snapshot.
76
+ * Included on INIT so the feature can render with the correct theme on first paint.
77
+ */
78
+ theme?: PluginThemeSnapshot;
79
+ };
80
+ type PluginThemeMode = "light" | "dark";
81
+ type PluginThemeSnapshot = {
82
+ mode: PluginThemeMode;
83
+ };
84
+ type PluginThemeColorRole = "solid" | "surface" | "border" | "text";
85
+ type PluginThemeMessage = {
86
+ type: "ENSERA_THEME";
87
+ instanceId?: string;
88
+ payload: {
89
+ theme: PluginThemeSnapshot;
90
+ };
74
91
  };
75
92
  /**
76
93
  * Launch modes for plugin instances
@@ -548,6 +565,28 @@ declare function useSyncedState<T extends JsonValue>(args: {
548
565
  initialState: T;
549
566
  }): [T, (state: T | ((prev: T) => T)) => void];
550
567
 
568
+ declare function normalizePluginThemeMode(value: unknown): PluginThemeMode;
569
+ declare function normalizePluginThemeSnapshot(value?: Partial<PluginThemeSnapshot> | PluginThemeMessage | null): PluginThemeSnapshot;
570
+ declare function applyPluginTheme(value?: Partial<PluginThemeSnapshot> | PluginThemeMessage | null, root?: HTMLElement): PluginThemeSnapshot;
571
+ declare function dispatchPluginThemeChange(value?: Partial<PluginThemeSnapshot> | PluginThemeMessage | null): PluginThemeSnapshot;
572
+ declare function initializePluginTheme(value?: Partial<PluginThemeSnapshot> | PluginThemeMessage | null): PluginThemeSnapshot;
573
+ declare function getPluginThemeSnapshot(): PluginThemeSnapshot;
574
+ declare function subscribePluginTheme(listener: () => void): () => boolean;
575
+ declare function usePluginTheme(): PluginThemeSnapshot;
576
+ declare function adaptFeatureColor(hex: string, args: {
577
+ mode: PluginThemeMode;
578
+ role?: PluginThemeColorRole;
579
+ }): string;
580
+ declare function getReadableFeatureTextColor(backgroundHex: string): "#FFFFFF" | "#111111";
581
+ declare function getFeatureColorTokens(hex: string, mode: PluginThemeMode): {
582
+ solid: string;
583
+ surface: string;
584
+ border: string;
585
+ text: string;
586
+ contrastText: string;
587
+ };
588
+ declare function syncAdaptiveFeatureColors(root: ParentNode | null | undefined, mode: PluginThemeMode): void;
589
+
551
590
  declare const tokens: {
552
591
  readonly spacing: {
553
592
  readonly xs: 4;
@@ -749,4 +788,4 @@ declare function setupContextMenuRelay(ctx: {
749
788
  instanceId: string;
750
789
  }): () => void;
751
790
 
752
- export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, ContextMenuShell, ContextRow, type ContextRowProps, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, Input, type InputProps, type InputSize, type InputVariant, type JsonObject, type JsonValue, type NotificationAction, type NotificationCapabilities, type NotificationTypeConfig, type PluginActionHandler, type PluginActionHandlerArgs, type PluginActionId, type PluginActionsMap, PluginAuthError, type PluginCtx, type PluginDispatchFn, type PluginDispatchRequest, type PluginDispatchResult, type PluginErrorPayload, PluginFetchError, type PluginFetchExpect, PluginFetchInputError, type PluginFetchOptions, type PluginFetchResponse, type PluginFetchRetry, PluginForbiddenError, type PluginLaunch, type PluginLogLevel, type PluginLogger, PluginNetworkError, PluginNotFoundError, type PluginNotification, type PluginNotificationBulkResponse, type PluginNotificationOptions, type PluginNotificationRequest, type PluginNotificationResponse, type PluginNotificationResultMessage, type PluginNotify, type PluginOpenOverlayMessage, PluginRateLimitError, PluginResponseError, type PluginRuntime, PluginServerError, type PluginStorage, type PluginStorageBackend, PluginStorageError, type PluginStorageIndexedDB, PluginStorageQuotaError, PluginUnknownActionError, PluginValidationError, Row, type RowAlign, type RowHeight, type RowJustify, type RowProps, type SyncCallback, type SyncEventType, type SyncMessage, type SyncPayload, type SyncedState, type Tokens, attachActionDispatcher, broadcast, createPluginFetch, createPluginLogger, createPluginNotify, createPluginRuntime, createPluginStorage, createPluginStorageIndexedDB, createSyncedState, defineActions, initBroadcast, makeStorageNamespace, onBroadcast, openOverlay, runActionSafe, setupContextMenuRelay, tokens, useBroadcastListener, useSyncedState };
791
+ export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, ContextMenuShell, ContextRow, type ContextRowProps, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, Input, type InputProps, type InputSize, type InputVariant, type JsonObject, type JsonValue, type NotificationAction, type NotificationCapabilities, type NotificationTypeConfig, type PluginActionHandler, type PluginActionHandlerArgs, type PluginActionId, type PluginActionsMap, PluginAuthError, type PluginCtx, type PluginDispatchFn, type PluginDispatchRequest, type PluginDispatchResult, type PluginErrorPayload, PluginFetchError, type PluginFetchExpect, PluginFetchInputError, type PluginFetchOptions, type PluginFetchResponse, type PluginFetchRetry, PluginForbiddenError, type PluginLaunch, type PluginLogLevel, type PluginLogger, PluginNetworkError, PluginNotFoundError, type PluginNotification, type PluginNotificationBulkResponse, type PluginNotificationOptions, type PluginNotificationRequest, type PluginNotificationResponse, type PluginNotificationResultMessage, type PluginNotify, type PluginOpenOverlayMessage, PluginRateLimitError, PluginResponseError, type PluginRuntime, PluginServerError, type PluginStorage, type PluginStorageBackend, PluginStorageError, type PluginStorageIndexedDB, PluginStorageQuotaError, type PluginThemeColorRole, type PluginThemeMessage, type PluginThemeMode, type PluginThemeSnapshot, PluginUnknownActionError, PluginValidationError, Row, type RowAlign, type RowHeight, type RowJustify, type RowProps, type SyncCallback, type SyncEventType, type SyncMessage, type SyncPayload, type SyncedState, type Tokens, adaptFeatureColor, applyPluginTheme, attachActionDispatcher, broadcast, createPluginFetch, createPluginLogger, createPluginNotify, createPluginRuntime, createPluginStorage, createPluginStorageIndexedDB, createSyncedState, defineActions, dispatchPluginThemeChange, getFeatureColorTokens, getPluginThemeSnapshot, getReadableFeatureTextColor, initBroadcast, initializePluginTheme, makeStorageNamespace, normalizePluginThemeMode, normalizePluginThemeSnapshot, onBroadcast, openOverlay, runActionSafe, setupContextMenuRelay, subscribePluginTheme, syncAdaptiveFeatureColors, tokens, useBroadcastListener, usePluginTheme, useSyncedState };
package/dist/index.js CHANGED
@@ -1260,6 +1260,327 @@ function useSyncedState(args) {
1260
1260
  return [sync.getState(), sync.setState];
1261
1261
  }
1262
1262
 
1263
+ // src/theme.ts
1264
+ import { useSyncExternalStore } from "react";
1265
+ var THEME_EVENT = "ENSERA_THEME_CHANGE";
1266
+ var THEME_ATTR = "data-ensera-theme";
1267
+ var DARK_ROOT_CLASS = "dark";
1268
+ var LIGHT_SURFACE = "#FFFFFF";
1269
+ var DARK_SURFACE = "#111827";
1270
+ var currentTheme = readThemeFromDom();
1271
+ var boundWindowListeners = false;
1272
+ var listeners = /* @__PURE__ */ new Set();
1273
+ function clamp(value, min, max) {
1274
+ return Math.min(max, Math.max(min, value));
1275
+ }
1276
+ function normalizeChannel(value) {
1277
+ return parseInt(value, 16);
1278
+ }
1279
+ function normalizePluginThemeMode(value) {
1280
+ return value === "dark" ? "dark" : "light";
1281
+ }
1282
+ function normalizePluginThemeSnapshot(value) {
1283
+ const maybeTheme = value && "payload" in value ? value.payload?.theme : value ?? void 0;
1284
+ return {
1285
+ mode: normalizePluginThemeMode(maybeTheme?.mode)
1286
+ };
1287
+ }
1288
+ function readThemeFromDom() {
1289
+ if (typeof document === "undefined") {
1290
+ return { mode: "light" };
1291
+ }
1292
+ const mode = document.documentElement.getAttribute(THEME_ATTR);
1293
+ return { mode: normalizePluginThemeMode(mode) };
1294
+ }
1295
+ function notifyThemeListeners() {
1296
+ for (const listener of listeners) {
1297
+ listener();
1298
+ }
1299
+ }
1300
+ function applyThemeToRoot(root, theme) {
1301
+ root.setAttribute(THEME_ATTR, theme.mode);
1302
+ root.classList.toggle(DARK_ROOT_CLASS, theme.mode === "dark");
1303
+ root.style.colorScheme = theme.mode;
1304
+ }
1305
+ function bindWindowThemeListeners() {
1306
+ if (boundWindowListeners || typeof window === "undefined") {
1307
+ return;
1308
+ }
1309
+ window.addEventListener(THEME_EVENT, (event) => {
1310
+ const detail = event.detail;
1311
+ currentTheme = normalizePluginThemeSnapshot(detail);
1312
+ notifyThemeListeners();
1313
+ });
1314
+ boundWindowListeners = true;
1315
+ }
1316
+ function applyPluginTheme(value, root) {
1317
+ const theme = normalizePluginThemeSnapshot(value);
1318
+ currentTheme = theme;
1319
+ if (typeof document !== "undefined") {
1320
+ applyThemeToRoot(root ?? document.documentElement, theme);
1321
+ }
1322
+ notifyThemeListeners();
1323
+ return theme;
1324
+ }
1325
+ function dispatchPluginThemeChange(value) {
1326
+ const theme = normalizePluginThemeSnapshot(value);
1327
+ currentTheme = theme;
1328
+ if (typeof window !== "undefined") {
1329
+ window.dispatchEvent(
1330
+ new CustomEvent(THEME_EVENT, {
1331
+ detail: theme
1332
+ })
1333
+ );
1334
+ } else {
1335
+ notifyThemeListeners();
1336
+ }
1337
+ return theme;
1338
+ }
1339
+ function initializePluginTheme(value) {
1340
+ bindWindowThemeListeners();
1341
+ if (value) {
1342
+ return applyPluginTheme(value);
1343
+ }
1344
+ currentTheme = readThemeFromDom();
1345
+ notifyThemeListeners();
1346
+ return currentTheme;
1347
+ }
1348
+ function getPluginThemeSnapshot() {
1349
+ bindWindowThemeListeners();
1350
+ return currentTheme;
1351
+ }
1352
+ function subscribePluginTheme(listener) {
1353
+ bindWindowThemeListeners();
1354
+ listeners.add(listener);
1355
+ return () => listeners.delete(listener);
1356
+ }
1357
+ function usePluginTheme() {
1358
+ bindWindowThemeListeners();
1359
+ return useSyncExternalStore(
1360
+ subscribePluginTheme,
1361
+ getPluginThemeSnapshot,
1362
+ getPluginThemeSnapshot
1363
+ );
1364
+ }
1365
+ function normalizeHexColor(value) {
1366
+ const raw = String(value ?? "").trim().replace(/^#/, "");
1367
+ if (raw.length === 3) {
1368
+ return `#${raw.split("").map((part) => `${part}${part}`).join("").toUpperCase()}`;
1369
+ }
1370
+ if (raw.length !== 6 || /[^0-9A-Fa-f]/.test(raw)) {
1371
+ return null;
1372
+ }
1373
+ return `#${raw.toUpperCase()}`;
1374
+ }
1375
+ function parseCssColorToHex(value) {
1376
+ const normalizedHex = normalizeHexColor(value);
1377
+ if (normalizedHex) return normalizedHex;
1378
+ const match = String(value ?? "").trim().match(/^rgba?\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
1379
+ if (!match) return null;
1380
+ return rgbToHex(Number(match[1]), Number(match[2]), Number(match[3]));
1381
+ }
1382
+ function hexToRgb(hex) {
1383
+ const normalized = normalizeHexColor(hex);
1384
+ if (!normalized) return null;
1385
+ return {
1386
+ r: normalizeChannel(normalized.slice(1, 3)),
1387
+ g: normalizeChannel(normalized.slice(3, 5)),
1388
+ b: normalizeChannel(normalized.slice(5, 7))
1389
+ };
1390
+ }
1391
+ function rgbToHex(r, g, b) {
1392
+ const toHex = (value) => clamp(Math.round(value), 0, 255).toString(16).padStart(2, "0");
1393
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
1394
+ }
1395
+ function rgbToHsl(r, g, b) {
1396
+ const rn = r / 255;
1397
+ const gn = g / 255;
1398
+ const bn = b / 255;
1399
+ const max = Math.max(rn, gn, bn);
1400
+ const min = Math.min(rn, gn, bn);
1401
+ const delta = max - min;
1402
+ const lightness = (max + min) / 2;
1403
+ if (delta === 0) {
1404
+ return { h: 0, s: 0, l: lightness };
1405
+ }
1406
+ const saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);
1407
+ let hue = 0;
1408
+ switch (max) {
1409
+ case rn:
1410
+ hue = (gn - bn) / delta + (gn < bn ? 6 : 0);
1411
+ break;
1412
+ case gn:
1413
+ hue = (bn - rn) / delta + 2;
1414
+ break;
1415
+ default:
1416
+ hue = (rn - gn) / delta + 4;
1417
+ break;
1418
+ }
1419
+ hue /= 6;
1420
+ return { h: hue, s: saturation, l: lightness };
1421
+ }
1422
+ function hslToRgb(h, s, l) {
1423
+ if (s === 0) {
1424
+ const value = l * 255;
1425
+ return { r: value, g: value, b: value };
1426
+ }
1427
+ const hueToRgb = (p2, q2, t) => {
1428
+ let next = t;
1429
+ if (next < 0) next += 1;
1430
+ if (next > 1) next -= 1;
1431
+ if (next < 1 / 6) return p2 + (q2 - p2) * 6 * next;
1432
+ if (next < 1 / 2) return q2;
1433
+ if (next < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - next) * 6;
1434
+ return p2;
1435
+ };
1436
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1437
+ const p = 2 * l - q;
1438
+ return {
1439
+ r: hueToRgb(p, q, h + 1 / 3) * 255,
1440
+ g: hueToRgb(p, q, h) * 255,
1441
+ b: hueToRgb(p, q, h - 1 / 3) * 255
1442
+ };
1443
+ }
1444
+ function mixColors(baseHex, mixHex, ratio) {
1445
+ const base = hexToRgb(baseHex);
1446
+ const mix = hexToRgb(mixHex);
1447
+ if (!base || !mix) return normalizeHexColor(baseHex) ?? baseHex;
1448
+ const clampedRatio = clamp(ratio, 0, 1);
1449
+ const inverse = 1 - clampedRatio;
1450
+ return rgbToHex(
1451
+ base.r * inverse + mix.r * clampedRatio,
1452
+ base.g * inverse + mix.g * clampedRatio,
1453
+ base.b * inverse + mix.b * clampedRatio
1454
+ );
1455
+ }
1456
+ function toLinear(channel) {
1457
+ const normalized = channel / 255;
1458
+ return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
1459
+ }
1460
+ function relativeLuminance(hex) {
1461
+ const rgb = hexToRgb(hex);
1462
+ if (!rgb) return 0;
1463
+ const r = toLinear(rgb.r);
1464
+ const g = toLinear(rgb.g);
1465
+ const b = toLinear(rgb.b);
1466
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
1467
+ }
1468
+ function contrastRatio(foregroundHex, backgroundHex) {
1469
+ const foreground = relativeLuminance(foregroundHex);
1470
+ const background = relativeLuminance(backgroundHex);
1471
+ const lighter = Math.max(foreground, background);
1472
+ const darker = Math.min(foreground, background);
1473
+ return (lighter + 0.05) / (darker + 0.05);
1474
+ }
1475
+ function ensureContrast(foregroundHex, backgroundHex, minRatio) {
1476
+ const normalizedForeground = normalizeHexColor(foregroundHex) ?? normalizeHexColor(backgroundHex) ?? "#000000";
1477
+ const normalizedBackground = normalizeHexColor(backgroundHex) ?? DARK_SURFACE;
1478
+ if (contrastRatio(normalizedForeground, normalizedBackground) >= minRatio) {
1479
+ return normalizedForeground;
1480
+ }
1481
+ const backgroundIsDark = relativeLuminance(normalizedBackground) < relativeLuminance(normalizedForeground);
1482
+ const targetMix = backgroundIsDark ? LIGHT_SURFACE : "#111111";
1483
+ let next = normalizedForeground;
1484
+ for (let index = 1; index <= 12; index += 1) {
1485
+ next = mixColors(normalizedForeground, targetMix, index * 0.06);
1486
+ if (contrastRatio(next, normalizedBackground) >= minRatio) {
1487
+ return next;
1488
+ }
1489
+ }
1490
+ return next;
1491
+ }
1492
+ function adaptSolidColor(hex, mode) {
1493
+ const normalized = normalizeHexColor(hex);
1494
+ if (!normalized) return hex;
1495
+ const rgb = hexToRgb(normalized);
1496
+ if (!rgb) return normalized;
1497
+ const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
1498
+ let nextLightness = hsl.l;
1499
+ let nextSaturation = hsl.s;
1500
+ if (mode === "light" && hsl.l < 0.42) {
1501
+ nextLightness = 0.56;
1502
+ nextSaturation = clamp(hsl.s * 0.96, 0, 1);
1503
+ } else if (mode === "dark" && hsl.l > 0.72) {
1504
+ nextLightness = 0.56;
1505
+ nextSaturation = clamp(hsl.s * 0.94, 0, 1);
1506
+ }
1507
+ const nextRgb = hslToRgb(hsl.h, nextSaturation, nextLightness);
1508
+ return rgbToHex(nextRgb.r, nextRgb.g, nextRgb.b);
1509
+ }
1510
+ function adaptFeatureColor(hex, args) {
1511
+ const role = args.role ?? "solid";
1512
+ const solid = adaptSolidColor(hex, args.mode);
1513
+ const surfaceBase = args.mode === "dark" ? DARK_SURFACE : LIGHT_SURFACE;
1514
+ switch (role) {
1515
+ case "surface":
1516
+ return mixColors(solid, surfaceBase, args.mode === "dark" ? 0.78 : 0.86);
1517
+ case "border":
1518
+ return mixColors(solid, surfaceBase, args.mode === "dark" ? 0.52 : 0.6);
1519
+ case "text":
1520
+ return ensureContrast(
1521
+ solid,
1522
+ surfaceBase,
1523
+ args.mode === "dark" ? 4 : 4.5
1524
+ );
1525
+ case "solid":
1526
+ default:
1527
+ return solid;
1528
+ }
1529
+ }
1530
+ function getReadableFeatureTextColor(backgroundHex) {
1531
+ const lightContrast = contrastRatio(LIGHT_SURFACE, backgroundHex);
1532
+ const darkContrast = contrastRatio("#111111", backgroundHex);
1533
+ return lightContrast >= darkContrast ? LIGHT_SURFACE : "#111111";
1534
+ }
1535
+ function getFeatureColorTokens(hex, mode) {
1536
+ const solid = adaptFeatureColor(hex, { mode, role: "solid" });
1537
+ const surface = adaptFeatureColor(hex, { mode, role: "surface" });
1538
+ const border = adaptFeatureColor(hex, { mode, role: "border" });
1539
+ const text = adaptFeatureColor(hex, { mode, role: "text" });
1540
+ return {
1541
+ solid,
1542
+ surface,
1543
+ border,
1544
+ text,
1545
+ contrastText: getReadableFeatureTextColor(solid)
1546
+ };
1547
+ }
1548
+ function syncAdaptiveFeatureColors(root, mode) {
1549
+ if (!root || typeof root.querySelectorAll !== "function") {
1550
+ return;
1551
+ }
1552
+ const elements = root.querySelectorAll("[style]");
1553
+ for (const element of elements) {
1554
+ const originalStyle = element.getAttribute("style");
1555
+ if (!originalStyle) continue;
1556
+ const colorMatch = originalStyle.match(/(?:^|;)\s*color:\s*([^;]+)/i);
1557
+ const backgroundMatch = originalStyle.match(
1558
+ /(?:^|;)\s*background-color:\s*([^;]+)/i
1559
+ );
1560
+ if (colorMatch) {
1561
+ const raw = element.dataset.enseraThemeColor ?? parseCssColorToHex(colorMatch[1]) ?? void 0;
1562
+ if (raw) {
1563
+ element.dataset.enseraThemeColor = raw;
1564
+ element.style.color = adaptFeatureColor(raw, {
1565
+ mode,
1566
+ role: "text"
1567
+ });
1568
+ }
1569
+ }
1570
+ if (backgroundMatch) {
1571
+ const raw = element.dataset.enseraThemeBackground ?? parseCssColorToHex(backgroundMatch[1]) ?? void 0;
1572
+ if (raw) {
1573
+ element.dataset.enseraThemeBackground = raw;
1574
+ element.style.backgroundColor = adaptFeatureColor(raw, {
1575
+ mode,
1576
+ role: "surface"
1577
+ });
1578
+ }
1579
+ }
1580
+ }
1581
+ }
1582
+ bindWindowThemeListeners();
1583
+
1263
1584
  // src/ui/tokens.ts
1264
1585
  var tokens = {
1265
1586
  // Spacing scale (in pixels)
@@ -1999,6 +2320,8 @@ export {
1999
2320
  PluginUnknownActionError,
2000
2321
  PluginValidationError,
2001
2322
  Row,
2323
+ adaptFeatureColor,
2324
+ applyPluginTheme,
2002
2325
  attachActionDispatcher,
2003
2326
  broadcast,
2004
2327
  createPluginFetch,
@@ -2009,13 +2332,23 @@ export {
2009
2332
  createPluginStorageIndexedDB,
2010
2333
  createSyncedState,
2011
2334
  defineActions,
2335
+ dispatchPluginThemeChange,
2336
+ getFeatureColorTokens,
2337
+ getPluginThemeSnapshot,
2338
+ getReadableFeatureTextColor,
2012
2339
  initBroadcast,
2340
+ initializePluginTheme,
2013
2341
  makeStorageNamespace,
2342
+ normalizePluginThemeMode,
2343
+ normalizePluginThemeSnapshot,
2014
2344
  onBroadcast,
2015
2345
  openOverlay,
2016
2346
  runActionSafe,
2017
2347
  setupContextMenuRelay,
2348
+ subscribePluginTheme,
2349
+ syncAdaptiveFeatureColors,
2018
2350
  tokens,
2019
2351
  useBroadcastListener,
2352
+ usePluginTheme,
2020
2353
  useSyncedState
2021
2354
  };
package/package.json CHANGED
@@ -1,50 +1,50 @@
1
- {
2
- "name": "@ensera/plugin-frontend",
3
- "version": "1.0.0",
4
- "description": "Runtime frontend SDK for Ensera plugins.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js"
13
- },
14
- "./package.json": "./package.json"
15
- },
16
- "files": [
17
- "dist",
18
- "README.md"
19
- ],
20
- "sideEffects": false,
21
- "scripts": {
22
- "build": "tsup src/index.ts --format esm --dts --clean --target es2022 --outDir dist",
23
- "dev": "tsup src/index.ts --format esm --dts --watch --target es2022 --outDir dist",
24
- "typecheck": "tsc -p tsconfig.json --noEmit",
25
- "prepublishOnly": "npm run build && npm run typecheck"
26
- },
27
- "keywords": [
28
- "ensera",
29
- "frontend",
30
- "sdk",
31
- "plugin",
32
- "react"
33
- ],
34
- "publishConfig": {
35
- "access": "public"
36
- },
37
- "engines": {
38
- "node": ">=18"
39
- },
40
- "peerDependencies": {
41
- "react": "^18.0.0",
42
- "react-dom": "^18.0.0"
43
- },
44
- "devDependencies": {
45
- "@types/react": "^18.3.28",
46
- "@types/react-dom": "^18.3.7",
47
- "react": "^18.3.1",
48
- "react-dom": "^18.3.1"
49
- }
50
- }
1
+ {
2
+ "name": "@ensera/plugin-frontend",
3
+ "version": "1.0.1",
4
+ "description": "Runtime frontend SDK for Ensera plugins.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./package.json": "./package.json"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "tsup src/index.ts --format esm --dts --clean --target es2022 --outDir dist",
23
+ "dev": "tsup src/index.ts --format esm --dts --watch --target es2022 --outDir dist",
24
+ "typecheck": "tsc -p tsconfig.json --noEmit",
25
+ "prepublishOnly": "npm run build && npm run typecheck"
26
+ },
27
+ "keywords": [
28
+ "ensera",
29
+ "frontend",
30
+ "sdk",
31
+ "plugin",
32
+ "react"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "peerDependencies": {
41
+ "react": "^18.0.0",
42
+ "react-dom": "^18.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/react": "^18.3.28",
46
+ "@types/react-dom": "^18.3.7",
47
+ "react": "^18.3.1",
48
+ "react-dom": "^18.3.1"
49
+ }
50
+ }