@stone-js/use-react 0.2.0 → 0.3.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/index.js CHANGED
@@ -1,11 +1,63 @@
1
- import { isNotEmpty, isEmpty, InitializationError, isMetaClassModule, isMetaFactoryModule, isFunctionModule, isObjectLikeModule, isFunction, mergeBlueprints, stoneBlueprint, classDecoratorLegacyWrapper, setMetadata, methodDecoratorLegacyWrapper, addMetadata, LIFECYCLE_HOOK_KEY, hasMetadata, getMetadata, isMatchedAdapter, Logger, addBlueprint } from '@stone-js/core';
1
+ import { InitializationError, isEmpty, isNotEmpty, isMetaClassModule, isMetaFactoryModule, isObjectLikeModule, isFunction, isFunctionModule, mergeBlueprints, stoneBlueprint, classDecoratorLegacyWrapper, setMetadata, methodDecoratorLegacyWrapper, addMetadata, LIFECYCLE_HOOK_KEY, hasMetadata, getMetadata, isMatchedAdapter, Logger, addBlueprint } from '@stone-js/core';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
  import { renderToString } from 'react-dom/server';
4
- import { createContext, StrictMode, useState, useEffect, useContext } from 'react';
5
- import { createRoot, hydrateRoot } from 'react-dom/client';
4
+ import { createContext, StrictMode, useContext, useMemo, useState, useEffect } from 'react';
5
+ import { hydrateRoot, createRoot } from 'react-dom/client';
6
6
  import { Config } from '@stone-js/config';
7
7
  import { GET, NODE_CONSOLE_PLATFORM, Router, RouteEvent } from '@stone-js/router';
8
- import { OutgoingHttpResponse, RedirectResponse, MetaStaticFileMiddleware, MetaCompressionMiddleware } from '@stone-js/http-core';
8
+ import { RedirectResponse, OutgoingHttpResponse, MetaCompressionMiddleware, MetaStaticFileMiddleware } from '@stone-js/http-core';
9
+
10
+ /**
11
+ * Custom error for react operations.
12
+ */
13
+ class UseReactError extends InitializationError {
14
+ constructor(message, options) {
15
+ super(message, options);
16
+ this.name = 'UseReactError';
17
+ }
18
+ }
19
+
20
+ /**
21
+ * A useReact event handler for processing incoming events
22
+ * For single event handler.
23
+ *
24
+ * Multiple event handlers will be processed by the router.
25
+ *
26
+ * @template IncomingEventType - The type representing the incoming event.
27
+ * @template OutgoingResponseType - The type representing the outgoing response.
28
+ */
29
+ class UseReactEventHandler {
30
+ blueprint;
31
+ /**
32
+ * Constructs a `UseReactEventHandler` instance.
33
+ *
34
+ * @param options - The UseReactEventHandler options including blueprint.
35
+ */
36
+ constructor({ blueprint }) {
37
+ this.blueprint = blueprint;
38
+ }
39
+ /**
40
+ * Handle an incoming event.
41
+ *
42
+ * @returns The outgoing response.
43
+ */
44
+ handle() {
45
+ return this.getComponentEventHandler();
46
+ }
47
+ /**
48
+ * Get the component event handler.
49
+ *
50
+ * @returns The component event handler.
51
+ * @throws {UseReactError} If the component event handler is missing.
52
+ */
53
+ getComponentEventHandler() {
54
+ const handler = this.blueprint.get('stone.useReact.componentEventHandler');
55
+ if (isEmpty(handler)) {
56
+ throw new UseReactError('The component event handler is missing.');
57
+ }
58
+ return handler;
59
+ }
60
+ }
9
61
 
10
62
  /**
11
63
  * Stone DOM Attribute.
@@ -269,16 +321,6 @@ const StoneError = () => {
269
321
  return (jsxs(Fragment, { children: [jsx("h1", { children: "An error occured" }), jsx("p", { children: "Sorry, something went wrong." })] }));
270
322
  };
271
323
 
272
- /**
273
- * Custom error for react operations.
274
- */
275
- class UseReactError extends InitializationError {
276
- constructor(message, options) {
277
- super(message, options);
278
- this.name = 'UseReactError';
279
- }
280
- }
281
-
282
324
  /**
283
325
  * Build the React application for the current route.
284
326
  * Or for the main handler if the route is not defined.
@@ -710,48 +752,6 @@ class ReactRuntime {
710
752
  */
711
753
  const MetaReactRuntime = { module: ReactRuntime, isClass: true, alias: 'reactRuntime', singleton: true };
712
754
 
713
- /**
714
- * A useReact event handler for processing incoming events
715
- * For single event handler.
716
- *
717
- * Multiple event handlers will be processed by the router.
718
- *
719
- * @template IncomingEventType - The type representing the incoming event.
720
- * @template OutgoingResponseType - The type representing the outgoing response.
721
- */
722
- class UseReactEventHandler {
723
- blueprint;
724
- /**
725
- * Constructs a `UseReactEventHandler` instance.
726
- *
727
- * @param options - The UseReactEventHandler options including blueprint.
728
- */
729
- constructor({ blueprint }) {
730
- this.blueprint = blueprint;
731
- }
732
- /**
733
- * Handle an incoming event.
734
- *
735
- * @returns The outgoing response.
736
- */
737
- handle() {
738
- return this.getComponentEventHandler();
739
- }
740
- /**
741
- * Get the component event handler.
742
- *
743
- * @returns The component event handler.
744
- * @throws {UseReactError} If the component event handler is missing.
745
- */
746
- getComponentEventHandler() {
747
- const handler = this.blueprint.get('stone.useReact.componentEventHandler');
748
- if (isEmpty(handler)) {
749
- throw new UseReactError('The component event handler is missing.');
750
- }
751
- return handler;
752
- }
753
- }
754
-
755
755
  /**
756
756
  * Class representing an UseReactUseReactKernelErrorHandler.
757
757
  *
@@ -1098,30 +1098,6 @@ const REACT_ADAPTER_ERROR_PAGE_KEY = Symbol.for('ReactAdapterErrorPage');
1098
1098
  */
1099
1099
  const STONE_REACT_APP_KEY = Symbol.for('StoneReactApp');
1100
1100
 
1101
- /**
1102
- * A class decorator for defining a class as a React Handler layout.
1103
- *
1104
- * @param options - Configuration options for the layout definition.
1105
- * @returns A method decorator to be applied to a class method.
1106
- *
1107
- * @example
1108
- * ```typescript
1109
- * import { AdapterErrorPage } from '@stone-js/use-react';
1110
- *
1111
- * @AdapterErrorPage({ error: 'UserNotFoundError' })
1112
- * class UserAdapterErrorPage {
1113
- * render({ error }) {
1114
- * return <h1>User name: {error.message}</h1>;
1115
- * }
1116
- * }
1117
- * ```
1118
- */
1119
- const AdapterErrorPage = (options) => {
1120
- return classDecoratorLegacyWrapper((_target, context) => {
1121
- setMetadata(context, REACT_ADAPTER_ERROR_PAGE_KEY, { ...options, isClass: true });
1122
- });
1123
- };
1124
-
1125
1101
  /**
1126
1102
  * A class decorator for defining a class as a React Handler layout.
1127
1103
  *
@@ -1147,37 +1123,24 @@ const ErrorPage = (options) => {
1147
1123
  };
1148
1124
 
1149
1125
  /**
1150
- * A class decorator for defining a class as a React Page route action.
1151
- * Uses the `Match` decorator internally to register the route with the HTTP `GET` method.
1152
- *
1153
- * @param options - Configuration options for the route definition, excluding the `methods` property.
1154
- * @returns A method decorator to be applied to a class method.
1126
+ * Hook decorator to mark a method as a lifecycle hook
1127
+ * And automatically add it to the global lifecycle hook registry.
1155
1128
  *
1156
1129
  * @example
1157
1130
  * ```typescript
1158
- * import { Page } from '@stone-js/use-react';
1159
- *
1160
- * @Page('/user-profile')
1161
- * class UserPage {
1162
- * handle({ event }): Record<string, string> {
1163
- * return { name: 'Jane Doe' };
1164
- * }
1165
- *
1166
- * render({ data }) {
1167
- * return <h1>User name: {data.name}</h1>;
1168
- * }
1131
+ * class MyClass {
1132
+ * // ...
1133
+ * @Hook('onPreparingPage')
1134
+ * onPreparingPage () {}
1169
1135
  * }
1170
1136
  * ```
1137
+ *
1138
+ * @param name - The name of the lifecycle hook.
1139
+ * @returns A class decorator function that sets the metadata using the provided options.
1171
1140
  */
1172
- const Page = (path, options = {}) => {
1173
- return classDecoratorLegacyWrapper((target, context) => {
1174
- setMetadata(context, REACT_PAGE_KEY, {
1175
- ...options,
1176
- path,
1177
- method: GET,
1178
- methods: [],
1179
- handler: { isClass: true, isComponent: true, layout: options.layout, module: target }
1180
- });
1141
+ const Hook = (name) => {
1142
+ return methodDecoratorLegacyWrapper((_target, context) => {
1143
+ addMetadata(context, LIFECYCLE_HOOK_KEY, { name, method: context.name });
1181
1144
  });
1182
1145
  };
1183
1146
 
@@ -1206,24 +1169,26 @@ const PageLayout = (options) => {
1206
1169
  };
1207
1170
 
1208
1171
  /**
1209
- * Hook decorator to mark a method as a lifecycle hook
1210
- * And automatically add it to the global lifecycle hook registry.
1172
+ * A class decorator for defining a class as a React Handler layout.
1173
+ *
1174
+ * @param options - Configuration options for the layout definition.
1175
+ * @returns A method decorator to be applied to a class method.
1211
1176
  *
1212
1177
  * @example
1213
1178
  * ```typescript
1214
- * class MyClass {
1215
- * // ...
1216
- * @Hook('onPreparingPage')
1217
- * onPreparingPage () {}
1179
+ * import { AdapterErrorPage } from '@stone-js/use-react';
1180
+ *
1181
+ * @AdapterErrorPage({ error: 'UserNotFoundError' })
1182
+ * class UserAdapterErrorPage {
1183
+ * render({ error }) {
1184
+ * return <h1>User name: {error.message}</h1>;
1185
+ * }
1218
1186
  * }
1219
1187
  * ```
1220
- *
1221
- * @param name - The name of the lifecycle hook.
1222
- * @returns A class decorator function that sets the metadata using the provided options.
1223
1188
  */
1224
- const Hook = (name) => {
1225
- return methodDecoratorLegacyWrapper((_target, context) => {
1226
- addMetadata(context, LIFECYCLE_HOOK_KEY, { name, method: context.name });
1189
+ const AdapterErrorPage = (options) => {
1190
+ return classDecoratorLegacyWrapper((_target, context) => {
1191
+ setMetadata(context, REACT_ADAPTER_ERROR_PAGE_KEY, { ...options, isClass: true });
1227
1192
  });
1228
1193
  };
1229
1194
 
@@ -1256,6 +1221,41 @@ const PageStatus = (statusCode = 200, headers = {}) => {
1256
1221
  });
1257
1222
  };
1258
1223
 
1224
+ /**
1225
+ * A class decorator for defining a class as a React Page route action.
1226
+ * Uses the `Match` decorator internally to register the route with the HTTP `GET` method.
1227
+ *
1228
+ * @param options - Configuration options for the route definition, excluding the `methods` property.
1229
+ * @returns A method decorator to be applied to a class method.
1230
+ *
1231
+ * @example
1232
+ * ```typescript
1233
+ * import { Page } from '@stone-js/use-react';
1234
+ *
1235
+ * @Page('/user-profile')
1236
+ * class UserPage {
1237
+ * handle({ event }): Record<string, string> {
1238
+ * return { name: 'Jane Doe' };
1239
+ * }
1240
+ *
1241
+ * render({ data }) {
1242
+ * return <h1>User name: {data.name}</h1>;
1243
+ * }
1244
+ * }
1245
+ * ```
1246
+ */
1247
+ const Page = (path, options = {}) => {
1248
+ return classDecoratorLegacyWrapper((target, context) => {
1249
+ setMetadata(context, REACT_PAGE_KEY, {
1250
+ ...options,
1251
+ path,
1252
+ method: GET,
1253
+ methods: [],
1254
+ handler: { isClass: true, isComponent: true, layout: options.layout, module: target }
1255
+ });
1256
+ });
1257
+ };
1258
+
1259
1259
  /**
1260
1260
  * Decorator to create a snapshot of the current data.
1261
1261
  *
@@ -1285,6 +1285,111 @@ const Snapshot = (name) => {
1285
1285
  });
1286
1286
  };
1287
1287
 
1288
+ /**
1289
+ * Sets the error handler for the React adapter and registers error pages.
1290
+ *
1291
+ * @param errorHandler - The error handler to set for the React adapter.
1292
+ * @param context - The blueprint context containing modules and blueprint.
1293
+ * @returns The updated blueprint context with the error handler and error pages set.
1294
+ */
1295
+ function setUseReactAdapterErrorHandler(errorHandler, context) {
1296
+ context
1297
+ .blueprint
1298
+ .set('stone.adapter.errorHandlers.default', { module: errorHandler, isClass: true });
1299
+ context
1300
+ .modules
1301
+ .filter(module => hasMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY))
1302
+ .forEach(module => {
1303
+ const { error, layout, adapterAlias, platform } = getMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY, { error: 'default' });
1304
+ if (isMatchedAdapter(context.blueprint, platform, adapterAlias)) {
1305
+ Array(error).flat().forEach(name => {
1306
+ context
1307
+ .blueprint
1308
+ .set(`stone.useReact.adapterErrorPages.${name}`, { isClass: true, layout, module });
1309
+ });
1310
+ }
1311
+ });
1312
+ // Process both eager and lazy loaded error pages
1313
+ Object
1314
+ .keys(context.blueprint.get('stone.useReact.adapterErrorPages', {}))
1315
+ .forEach((name) => {
1316
+ context
1317
+ .blueprint
1318
+ .set(`stone.adapter.errorHandlers.${name}`, { module: errorHandler, isClass: true });
1319
+ });
1320
+ return context;
1321
+ }
1322
+
1323
+ /**
1324
+ * Create an UseReact response.
1325
+ *
1326
+ * @param options - The options for creating the response.
1327
+ * @returns The React response.
1328
+ */
1329
+ const reactResponse = (options) => {
1330
+ if (isNotEmpty(options) &&
1331
+ (isNotEmpty(options.url) ||
1332
+ (isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
1333
+ return reactRedirectResponse(options);
1334
+ }
1335
+ return OutgoingHttpResponse.create(options);
1336
+ };
1337
+ /**
1338
+ * Create an UseReact redirect response.
1339
+ *
1340
+ * @param options - The options for creating the response.
1341
+ * @returns The React redirect response.
1342
+ */
1343
+ const reactRedirectResponse = (options) => {
1344
+ return RedirectResponse.create({ statusCode: 302, ...options });
1345
+ };
1346
+
1347
+ /**
1348
+ * Class representing an UseReactServerErrorHandler.
1349
+ *
1350
+ * Adapter level error handler for React applications.
1351
+ */
1352
+ class UseReactServerErrorHandler {
1353
+ logger;
1354
+ blueprint;
1355
+ /**
1356
+ * Create an UseReactServerErrorHandler.
1357
+ *
1358
+ * @param options - UseReactServerErrorHandler options.
1359
+ */
1360
+ constructor({ blueprint }) {
1361
+ this.blueprint = blueprint;
1362
+ this.logger = Logger.getInstance();
1363
+ }
1364
+ /**
1365
+ * Handle an error.
1366
+ *
1367
+ * @param error - The error to handle.
1368
+ * @param context - The context of the adapter.
1369
+ * @returns The raw response.
1370
+ */
1371
+ async handle(error, context) {
1372
+ this.logger.error(error.message, { error });
1373
+ return context
1374
+ .rawResponseBuilder
1375
+ .add('statusCode', error.statusCode ?? 500)
1376
+ .add('headers', new Headers({ 'Content-Type': 'text/html' }))
1377
+ .add('body', await this.getErrorBody(error, context));
1378
+ }
1379
+ /**
1380
+ * Get the error body.
1381
+ *
1382
+ * @param error - The error to handle.
1383
+ * @returns The error body.
1384
+ */
1385
+ async getErrorBody(error, context) {
1386
+ const statusCode = error.statusCode ?? 500;
1387
+ const template = htmlTemplate(this.blueprint);
1388
+ const ClientApp = await buildAdapterErrorComponent(this.blueprint, context, statusCode, error);
1389
+ return template.replace('<!--app-html-->', renderToString(ClientApp));
1390
+ }
1391
+ }
1392
+
1288
1393
  /**
1289
1394
  * Blueprint middleware to dynamically set lifecycle hooks for react.
1290
1395
  *
@@ -1416,111 +1521,6 @@ async function SetUseReactEventHandlerMiddleware(context, next) {
1416
1521
  return blueprint;
1417
1522
  }
1418
1523
 
1419
- /**
1420
- * Sets the error handler for the React adapter and registers error pages.
1421
- *
1422
- * @param errorHandler - The error handler to set for the React adapter.
1423
- * @param context - The blueprint context containing modules and blueprint.
1424
- * @returns The updated blueprint context with the error handler and error pages set.
1425
- */
1426
- function setUseReactAdapterErrorHandler(errorHandler, context) {
1427
- context
1428
- .blueprint
1429
- .set('stone.adapter.errorHandlers.default', { module: errorHandler, isClass: true });
1430
- context
1431
- .modules
1432
- .filter(module => hasMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY))
1433
- .forEach(module => {
1434
- const { error, layout, adapterAlias, platform } = getMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY, { error: 'default' });
1435
- if (isMatchedAdapter(context.blueprint, platform, adapterAlias)) {
1436
- Array(error).flat().forEach(name => {
1437
- context
1438
- .blueprint
1439
- .set(`stone.useReact.adapterErrorPages.${name}`, { isClass: true, layout, module });
1440
- });
1441
- }
1442
- });
1443
- // Process both eager and lazy loaded error pages
1444
- Object
1445
- .keys(context.blueprint.get('stone.useReact.adapterErrorPages', {}))
1446
- .forEach((name) => {
1447
- context
1448
- .blueprint
1449
- .set(`stone.adapter.errorHandlers.${name}`, { module: errorHandler, isClass: true });
1450
- });
1451
- return context;
1452
- }
1453
-
1454
- /**
1455
- * Create an UseReact response.
1456
- *
1457
- * @param options - The options for creating the response.
1458
- * @returns The React response.
1459
- */
1460
- const reactResponse = (options) => {
1461
- if (isNotEmpty(options) &&
1462
- (isNotEmpty(options.url) ||
1463
- (isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
1464
- return reactRedirectResponse(options);
1465
- }
1466
- return OutgoingHttpResponse.create(options);
1467
- };
1468
- /**
1469
- * Create an UseReact redirect response.
1470
- *
1471
- * @param options - The options for creating the response.
1472
- * @returns The React redirect response.
1473
- */
1474
- const reactRedirectResponse = (options) => {
1475
- return RedirectResponse.create({ statusCode: 302, ...options });
1476
- };
1477
-
1478
- /**
1479
- * Class representing an UseReactServerErrorHandler.
1480
- *
1481
- * Adapter level error handler for React applications.
1482
- */
1483
- class UseReactServerErrorHandler {
1484
- logger;
1485
- blueprint;
1486
- /**
1487
- * Create an UseReactServerErrorHandler.
1488
- *
1489
- * @param options - UseReactServerErrorHandler options.
1490
- */
1491
- constructor({ blueprint }) {
1492
- this.blueprint = blueprint;
1493
- this.logger = Logger.getInstance();
1494
- }
1495
- /**
1496
- * Handle an error.
1497
- *
1498
- * @param error - The error to handle.
1499
- * @param context - The context of the adapter.
1500
- * @returns The raw response.
1501
- */
1502
- async handle(error, context) {
1503
- this.logger.error(error.message, { error });
1504
- return context
1505
- .rawResponseBuilder
1506
- .add('statusCode', error.statusCode ?? 500)
1507
- .add('headers', new Headers({ 'Content-Type': 'text/html' }))
1508
- .add('body', await this.getErrorBody(error, context));
1509
- }
1510
- /**
1511
- * Get the error body.
1512
- *
1513
- * @param error - The error to handle.
1514
- * @returns The error body.
1515
- */
1516
- async getErrorBody(error, context) {
1517
- const statusCode = error.statusCode ?? 500;
1518
- const template = htmlTemplate(this.blueprint);
1519
- const ClientApp = await buildAdapterErrorComponent(this.blueprint, context, statusCode, error);
1520
- return template.replace('<!--app-html-->', renderToString(ClientApp));
1521
- }
1522
- }
1523
-
1524
1524
  /**
1525
1525
  * Blueprint middleware to process and register adapter error page definitions from modules.
1526
1526
  *
@@ -1624,6 +1624,47 @@ const StoneClient = ({ children }) => {
1624
1624
  return isClient() ? jsx(Fragment, { children: children }) : jsx(Fragment, {});
1625
1625
  };
1626
1626
 
1627
+ /**
1628
+ * Internal link component using Stone.js router.
1629
+ */
1630
+ const StoneLink = ({ to, href, noRel, external, children, ariaCurrentValue = 'page', selectedClass = 'selected', ...rest }) => {
1631
+ const isExternal = external === true;
1632
+ const shouldHandleNav = !isExternal && isNotEmpty(to);
1633
+ const router = useContext(StoneContext).container.resolve(Router);
1634
+ const path = useMemo(() => {
1635
+ return isObjectLikeModule(to) ? router.generate(to) : to ?? href ?? '#';
1636
+ }, [to, href, router]);
1637
+ const [currentRoute, setCurrentRoute] = useState(router.getCurrentRoute());
1638
+ const selectedClassName = currentRoute?.path === path ? selectedClass : undefined;
1639
+ const elemClassName = [rest.className, selectedClassName].filter(Boolean).join(' ').trim();
1640
+ const handleClick = (event) => {
1641
+ rest.onClick?.(event);
1642
+ if (event.defaultPrevented || isExternal)
1643
+ return;
1644
+ event.preventDefault();
1645
+ isNotEmpty(to) && router.navigate(to);
1646
+ };
1647
+ if (isEmpty(to) && isEmpty(href)) {
1648
+ Logger.warn('StoneLink: missing "to" or "href"');
1649
+ }
1650
+ useEffect(() => {
1651
+ const routerEventHandler = (event) => {
1652
+ setCurrentRoute(event.get('route'));
1653
+ };
1654
+ router.on(RouteEvent.ROUTED, routerEventHandler);
1655
+ return () => {
1656
+ router.off(RouteEvent.ROUTED, routerEventHandler);
1657
+ };
1658
+ }, [router]);
1659
+ return (
1660
+ // eslint-disable-next-line react/jsx-no-target-blank
1661
+ jsx("a", { ...rest, href: path, className: elemClassName, target: isExternal ? '_blank' : rest.target, "aria-current": isNotEmpty(selectedClassName) ? ariaCurrentValue : undefined, rel: noRel === true
1662
+ ? undefined
1663
+ : isExternal
1664
+ ? 'noopener noreferrer'
1665
+ : rest.rel, onClick: shouldHandleNav ? handleClick : rest.onClick, children: children }));
1666
+ };
1667
+
1627
1668
  /**
1628
1669
  * A dynamic rendering component that updates its content based on a global event.
1629
1670
  *
@@ -1636,7 +1677,7 @@ const StoneClient = ({ children }) => {
1636
1677
  * @param options - The options to create the Stone Outlet.
1637
1678
  * @returns The Stone Outlet component.
1638
1679
  */
1639
- const StoneOutlet = ({ children }) => {
1680
+ const StoneOutlet = ({ children, ...rest }) => {
1640
1681
  const [currentView, setCurrentView] = useState(children);
1641
1682
  useEffect(() => {
1642
1683
  const eventName = STONE_PAGE_EVENT_OUTLET;
@@ -1648,44 +1689,7 @@ const StoneOutlet = ({ children }) => {
1648
1689
  window.addEventListener(eventName, handleEvent);
1649
1690
  return () => window.removeEventListener(eventName, handleEvent);
1650
1691
  }, []);
1651
- return jsx("div", { "data-stone-outlet": 'true', children: currentView });
1652
- };
1653
-
1654
- /**
1655
- * Internal link component using Stone.js router.
1656
- */
1657
- const InternalLink = ({ to, href, noRel, children, className, defaultNav, selectedClass = 'selected', ariaCurrentValue = 'page', rel = 'noopener noreferrer' }) => {
1658
- const router = useContext(StoneContext).container.resolve(Router);
1659
- const path = isObjectLikeModule(to) ? router.generate(to) : to ?? href;
1660
- const [currentRoute, setCurrentRoute] = useState(router.getCurrentRoute());
1661
- const selectedClassName = currentRoute?.path === path ? selectedClass : undefined;
1662
- const elemClassName = [className, selectedClassName].filter(Boolean).join(' ').trim();
1663
- const handleClick = (event) => {
1664
- event.preventDefault();
1665
- router.navigate(to ?? '');
1666
- };
1667
- useEffect(() => {
1668
- const routerEventHandler = (event) => {
1669
- setCurrentRoute(event.get('route'));
1670
- };
1671
- router.on(RouteEvent.ROUTED, routerEventHandler);
1672
- return () => {
1673
- router.off(RouteEvent.ROUTED, routerEventHandler);
1674
- };
1675
- }, [router]);
1676
- return defaultNav === true
1677
- ? (jsx("a", { href: path, className: elemClassName, "aria-current": ariaCurrentValue, rel: noRel !== undefined ? undefined : rel, children: children }))
1678
- : (jsx("button", { onClick: handleClick, className: elemClassName, "aria-current": ariaCurrentValue, rel: noRel !== undefined ? undefined : rel, children: children }));
1679
- };
1680
- /**
1681
- * External link component rendering a regular <a> tag.
1682
- */
1683
- const ExternalLink = ({ to, href, noRel, target, children, className, ariaCurrentValue = 'page', rel = 'noopener noreferrer' }) => (jsx("a", { target: target, className: className, "aria-current": ariaCurrentValue, rel: noRel !== undefined ? undefined : rel, href: typeof to === 'string' ? to : href, children: children }));
1684
- /**
1685
- * Main StoneLink component delegating to internal or external versions.
1686
- */
1687
- const StoneLink = (props) => {
1688
- return props.external === true ? jsx(ExternalLink, { ...props }) : jsx(InternalLink, { ...props });
1692
+ return jsx("div", { ...rest, "data-stone-outlet": 'true', children: currentView });
1689
1693
  };
1690
1694
 
1691
1695
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stone-js/use-react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "React integration for Stone.js, universal rendering, SSR hydration, layouts, pages, snapshots, head management, and more.",
5
5
  "author": "Mr. Stone <evensstone@gmail.com>",
6
6
  "license": "MIT",
@@ -60,9 +60,9 @@
60
60
  "@stone-js/browser-adapter": "^0.1.0",
61
61
  "@stone-js/browser-core": "^0.1.1",
62
62
  "@stone-js/config": "^0.1.0",
63
- "@stone-js/core": "^0.1.1",
63
+ "@stone-js/core": "^0.1.4",
64
64
  "@stone-js/http-core": "^0.1.2",
65
- "@stone-js/router": "^0.1.0",
65
+ "@stone-js/router": "^0.2.0",
66
66
  "react": "^19.0.0",
67
67
  "react-dom": "^19.0.0"
68
68
  },
@@ -72,25 +72,25 @@
72
72
  "@rollup/plugin-commonjs": "^28.0.5",
73
73
  "@rollup/plugin-multi-entry": "^6.0.1",
74
74
  "@rollup/plugin-node-resolve": "^16.0.1",
75
- "@rollup/plugin-typescript": "^12.1.1",
75
+ "@rollup/plugin-typescript": "^12.1.4",
76
76
  "@testing-library/react": "^16.3.0",
77
- "@types/node": "^24.0.0",
77
+ "@types/node": "^24.0.7",
78
78
  "@types/react": "^19.0.7",
79
79
  "@types/react-dom": "^19.0.3",
80
- "@vitest/coverage-v8": "^3.2.3",
80
+ "@vitest/coverage-v8": "^3.2.4",
81
81
  "husky": "^9.1.7",
82
82
  "jsdom": "^26.1.0",
83
83
  "rimraf": "^6.0.1",
84
- "rollup": "^4.43.0",
84
+ "rollup": "^4.44.1",
85
85
  "rollup-plugin-delete": "^3.0.1",
86
86
  "rollup-plugin-dts": "^6.2.1",
87
- "rollup-plugin-node-externals": "^8.0.0",
87
+ "rollup-plugin-node-externals": "^8.0.1",
88
88
  "ts-standard": "^12.0.2",
89
89
  "tslib": "^2.8.1",
90
- "typedoc": "^0.28.5",
91
- "typedoc-plugin-markdown": "^4.6.4",
90
+ "typedoc": "^0.28.6",
91
+ "typedoc-plugin-markdown": "^4.7.0",
92
92
  "typescript": "^5.6.3",
93
- "vitest": "^3.2.3"
93
+ "vitest": "^3.2.4"
94
94
  },
95
95
  "ts-standard": {
96
96
  "globals": [