@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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/browser.js +157 -153
- package/dist/index.d.ts +262 -267
- package/dist/index.js +265 -261
- package/package.json +11 -11
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
[](https://www.npmjs.com/package/@stone-js/use-react)
|
|
5
5
|
[](https://www.npmjs.com/package/@stone-js/use-react)
|
|
6
|
-

|
|
7
7
|
[](https://github.com/stone-foundation/stone-js-use-react/actions/workflows/main.yml)
|
|
8
8
|
[](https://github.com/stone-foundation/stone-js-use-react/actions/workflows/release.yml)
|
|
9
9
|
[](https://sonarcloud.io/summary/new_code?id=stone-foundation_stone-js-use-react)
|
package/dist/browser.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
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 { isNotEmpty, isEmpty, InitializationError, isMetaClassModule, isMetaFactoryModule, isObjectLikeModule, isFunction, isFunctionModule, mergeBlueprints, stoneBlueprint, Logger, classDecoratorLegacyWrapper, setMetadata, methodDecoratorLegacyWrapper, addMetadata, LIFECYCLE_HOOK_KEY, hasMetadata, getMetadata, isMatchedAdapter, addBlueprint } from '@stone-js/core';
|
|
3
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
3
|
import { renderToString } from 'react-dom/server';
|
|
5
|
-
import {
|
|
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, NAVIGATION_EVENT, Router, RouteEvent } from '@stone-js/router';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Stone context.
|
|
12
|
-
* Usefull to pass data to the components.
|
|
13
|
-
*/
|
|
14
|
-
const StoneContext = createContext({});
|
|
8
|
+
import { RedirectBrowserResponse, OutgoingBrowserResponse } from '@stone-js/browser-core';
|
|
15
9
|
|
|
16
10
|
/**
|
|
17
11
|
* Stone DOM Attribute.
|
|
@@ -246,6 +240,12 @@ const STONE_SNAPSHOT = '__STONE_SNAPSHOT__';
|
|
|
246
240
|
*/
|
|
247
241
|
const STONE_PAGE_EVENT_OUTLET = 'stone:inject:react-page:outlet';
|
|
248
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Stone context.
|
|
245
|
+
* Usefull to pass data to the components.
|
|
246
|
+
*/
|
|
247
|
+
const StoneContext = createContext({});
|
|
248
|
+
|
|
249
249
|
/**
|
|
250
250
|
* Provides a scoped `StoneContext` for its children within a strict mode.
|
|
251
251
|
*
|
|
@@ -912,33 +912,6 @@ class UseReactServiceProvider {
|
|
|
912
912
|
*/
|
|
913
913
|
const MetaUseReactServiceProvider = { module: UseReactServiceProvider, isClass: true };
|
|
914
914
|
|
|
915
|
-
/**
|
|
916
|
-
* Utility function to define an adapter error page.
|
|
917
|
-
*
|
|
918
|
-
* @param module - The adapter error page module.
|
|
919
|
-
* @param options - Optional adapter error page options.
|
|
920
|
-
* @returns The UseReactBlueprint.
|
|
921
|
-
*/
|
|
922
|
-
function defineAdapterErrorPage(module, options) {
|
|
923
|
-
const error = options?.error ?? 'default';
|
|
924
|
-
const adapterErrorPages = Object.fromEntries([error].flat().map((err) => [
|
|
925
|
-
err,
|
|
926
|
-
{
|
|
927
|
-
...options,
|
|
928
|
-
module,
|
|
929
|
-
error: err,
|
|
930
|
-
isFactory: options?.isClass !== true
|
|
931
|
-
}
|
|
932
|
-
]));
|
|
933
|
-
return {
|
|
934
|
-
stone: {
|
|
935
|
-
useReact: {
|
|
936
|
-
adapterErrorPages
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
|
|
942
915
|
/**
|
|
943
916
|
* Default blueprint for a React-based Stone.js application.
|
|
944
917
|
*
|
|
@@ -993,6 +966,33 @@ function defineStoneReactApp(moduleOrOptions = {}, optionsOrBlueprints, maybeBlu
|
|
|
993
966
|
return mergeBlueprints(stoneBlueprint, internalUseReactBlueprint, ...blueprints, { stone: stonePart });
|
|
994
967
|
}
|
|
995
968
|
|
|
969
|
+
/**
|
|
970
|
+
* Utility function to define an adapter error page.
|
|
971
|
+
*
|
|
972
|
+
* @param module - The adapter error page module.
|
|
973
|
+
* @param options - Optional adapter error page options.
|
|
974
|
+
* @returns The UseReactBlueprint.
|
|
975
|
+
*/
|
|
976
|
+
function defineAdapterErrorPage(module, options) {
|
|
977
|
+
const error = options?.error ?? 'default';
|
|
978
|
+
const adapterErrorPages = Object.fromEntries([error].flat().map((err) => [
|
|
979
|
+
err,
|
|
980
|
+
{
|
|
981
|
+
...options,
|
|
982
|
+
module,
|
|
983
|
+
error: err,
|
|
984
|
+
isFactory: options?.isClass !== true
|
|
985
|
+
}
|
|
986
|
+
]));
|
|
987
|
+
return {
|
|
988
|
+
stone: {
|
|
989
|
+
useReact: {
|
|
990
|
+
adapterErrorPages
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
|
|
996
996
|
/**
|
|
997
997
|
* Utility function to define a page.
|
|
998
998
|
*
|
|
@@ -1073,6 +1073,73 @@ function defineErrorPage(module, options) {
|
|
|
1073
1073
|
};
|
|
1074
1074
|
}
|
|
1075
1075
|
|
|
1076
|
+
/**
|
|
1077
|
+
* Class representing an UseReactBrowserErrorHandler.
|
|
1078
|
+
*
|
|
1079
|
+
* Adapter level error handler for React applications.
|
|
1080
|
+
*/
|
|
1081
|
+
class UseReactBrowserErrorHandler {
|
|
1082
|
+
logger;
|
|
1083
|
+
blueprint;
|
|
1084
|
+
/**
|
|
1085
|
+
* Create an UseReactBrowserErrorHandler.
|
|
1086
|
+
*
|
|
1087
|
+
* @param options - UseReactBrowserErrorHandler options.
|
|
1088
|
+
*/
|
|
1089
|
+
constructor({ blueprint }) {
|
|
1090
|
+
this.blueprint = blueprint;
|
|
1091
|
+
this.logger = Logger.getInstance();
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Handle an error.
|
|
1095
|
+
*
|
|
1096
|
+
* @param error - The error to handle.
|
|
1097
|
+
* @param context - The context of the adapter.
|
|
1098
|
+
* @returns The raw response.
|
|
1099
|
+
*/
|
|
1100
|
+
async handle(error, context) {
|
|
1101
|
+
this.logger.error(error.message, { error });
|
|
1102
|
+
return context
|
|
1103
|
+
.rawResponseBuilder
|
|
1104
|
+
.add('render', async () => await this.renderError(error, context));
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Get the error body.
|
|
1108
|
+
*
|
|
1109
|
+
* @param error - The error to handle.
|
|
1110
|
+
* @returns The error body.
|
|
1111
|
+
*/
|
|
1112
|
+
async renderError(error, context) {
|
|
1113
|
+
const app = await buildAdapterErrorComponent(this.blueprint, context, error.statusCode ?? 500, error);
|
|
1114
|
+
// Render the component
|
|
1115
|
+
renderReactApp(app, this.blueprint);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Create an UseReact response.
|
|
1121
|
+
*
|
|
1122
|
+
* @param options - The options for creating the response.
|
|
1123
|
+
* @returns The React response.
|
|
1124
|
+
*/
|
|
1125
|
+
const reactResponse = (options) => {
|
|
1126
|
+
if (isNotEmpty(options) &&
|
|
1127
|
+
(isNotEmpty(options.url) ||
|
|
1128
|
+
(isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
|
|
1129
|
+
return reactRedirectResponse(options);
|
|
1130
|
+
}
|
|
1131
|
+
return OutgoingBrowserResponse.create(options);
|
|
1132
|
+
};
|
|
1133
|
+
/**
|
|
1134
|
+
* Create an UseReact redirect response.
|
|
1135
|
+
*
|
|
1136
|
+
* @param options - The options for creating the response.
|
|
1137
|
+
* @returns The React redirect response.
|
|
1138
|
+
*/
|
|
1139
|
+
const reactRedirectResponse = (options) => {
|
|
1140
|
+
return RedirectBrowserResponse.create({ statusCode: 302, ...options });
|
|
1141
|
+
};
|
|
1142
|
+
|
|
1076
1143
|
/**
|
|
1077
1144
|
* Constants are defined here to prevent Circular dependency between modules
|
|
1078
1145
|
* This pattern must be applied to all Stone libraries or third party libraries.
|
|
@@ -1285,65 +1352,6 @@ const Snapshot = (name) => {
|
|
|
1285
1352
|
});
|
|
1286
1353
|
};
|
|
1287
1354
|
|
|
1288
|
-
/**
|
|
1289
|
-
* Create an UseReact response.
|
|
1290
|
-
*
|
|
1291
|
-
* @param options - The options for creating the response.
|
|
1292
|
-
* @returns The React response.
|
|
1293
|
-
*/
|
|
1294
|
-
const reactResponse = (options) => {
|
|
1295
|
-
if (isNotEmpty(options) &&
|
|
1296
|
-
(isNotEmpty(options.url) ||
|
|
1297
|
-
(isNotEmpty(options.content) && isNotEmpty(options.content.redirect)))) {
|
|
1298
|
-
return reactRedirectResponse(options);
|
|
1299
|
-
}
|
|
1300
|
-
return OutgoingBrowserResponse.create(options);
|
|
1301
|
-
};
|
|
1302
|
-
/**
|
|
1303
|
-
* Create an UseReact redirect response.
|
|
1304
|
-
*
|
|
1305
|
-
* @param options - The options for creating the response.
|
|
1306
|
-
* @returns The React redirect response.
|
|
1307
|
-
*/
|
|
1308
|
-
const reactRedirectResponse = (options) => {
|
|
1309
|
-
return RedirectBrowserResponse.create({ statusCode: 302, ...options });
|
|
1310
|
-
};
|
|
1311
|
-
|
|
1312
|
-
/**
|
|
1313
|
-
* Sets the error handler for the React adapter and registers error pages.
|
|
1314
|
-
*
|
|
1315
|
-
* @param errorHandler - The error handler to set for the React adapter.
|
|
1316
|
-
* @param context - The blueprint context containing modules and blueprint.
|
|
1317
|
-
* @returns The updated blueprint context with the error handler and error pages set.
|
|
1318
|
-
*/
|
|
1319
|
-
function setUseReactAdapterErrorHandler(errorHandler, context) {
|
|
1320
|
-
context
|
|
1321
|
-
.blueprint
|
|
1322
|
-
.set('stone.adapter.errorHandlers.default', { module: errorHandler, isClass: true });
|
|
1323
|
-
context
|
|
1324
|
-
.modules
|
|
1325
|
-
.filter(module => hasMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY))
|
|
1326
|
-
.forEach(module => {
|
|
1327
|
-
const { error, layout, adapterAlias, platform } = getMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY, { error: 'default' });
|
|
1328
|
-
if (isMatchedAdapter(context.blueprint, platform, adapterAlias)) {
|
|
1329
|
-
Array(error).flat().forEach(name => {
|
|
1330
|
-
context
|
|
1331
|
-
.blueprint
|
|
1332
|
-
.set(`stone.useReact.adapterErrorPages.${name}`, { isClass: true, layout, module });
|
|
1333
|
-
});
|
|
1334
|
-
}
|
|
1335
|
-
});
|
|
1336
|
-
// Process both eager and lazy loaded error pages
|
|
1337
|
-
Object
|
|
1338
|
-
.keys(context.blueprint.get('stone.useReact.adapterErrorPages', {}))
|
|
1339
|
-
.forEach((name) => {
|
|
1340
|
-
context
|
|
1341
|
-
.blueprint
|
|
1342
|
-
.set(`stone.adapter.errorHandlers.${name}`, { module: errorHandler, isClass: true });
|
|
1343
|
-
});
|
|
1344
|
-
return context;
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
1355
|
/**
|
|
1348
1356
|
* Blueprint middleware to dynamically set lifecycle hooks for react.
|
|
1349
1357
|
*
|
|
@@ -1476,46 +1484,38 @@ async function SetUseReactEventHandlerMiddleware(context, next) {
|
|
|
1476
1484
|
}
|
|
1477
1485
|
|
|
1478
1486
|
/**
|
|
1479
|
-
*
|
|
1487
|
+
* Sets the error handler for the React adapter and registers error pages.
|
|
1480
1488
|
*
|
|
1481
|
-
*
|
|
1489
|
+
* @param errorHandler - The error handler to set for the React adapter.
|
|
1490
|
+
* @param context - The blueprint context containing modules and blueprint.
|
|
1491
|
+
* @returns The updated blueprint context with the error handler and error pages set.
|
|
1482
1492
|
*/
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
.
|
|
1506
|
-
.
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
* Get the error body.
|
|
1510
|
-
*
|
|
1511
|
-
* @param error - The error to handle.
|
|
1512
|
-
* @returns The error body.
|
|
1513
|
-
*/
|
|
1514
|
-
async renderError(error, context) {
|
|
1515
|
-
const app = await buildAdapterErrorComponent(this.blueprint, context, error.statusCode ?? 500, error);
|
|
1516
|
-
// Render the component
|
|
1517
|
-
renderReactApp(app, this.blueprint);
|
|
1518
|
-
}
|
|
1493
|
+
function setUseReactAdapterErrorHandler(errorHandler, context) {
|
|
1494
|
+
context
|
|
1495
|
+
.blueprint
|
|
1496
|
+
.set('stone.adapter.errorHandlers.default', { module: errorHandler, isClass: true });
|
|
1497
|
+
context
|
|
1498
|
+
.modules
|
|
1499
|
+
.filter(module => hasMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY))
|
|
1500
|
+
.forEach(module => {
|
|
1501
|
+
const { error, layout, adapterAlias, platform } = getMetadata(module, REACT_ADAPTER_ERROR_PAGE_KEY, { error: 'default' });
|
|
1502
|
+
if (isMatchedAdapter(context.blueprint, platform, adapterAlias)) {
|
|
1503
|
+
Array(error).flat().forEach(name => {
|
|
1504
|
+
context
|
|
1505
|
+
.blueprint
|
|
1506
|
+
.set(`stone.useReact.adapterErrorPages.${name}`, { isClass: true, layout, module });
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
// Process both eager and lazy loaded error pages
|
|
1511
|
+
Object
|
|
1512
|
+
.keys(context.blueprint.get('stone.useReact.adapterErrorPages', {}))
|
|
1513
|
+
.forEach((name) => {
|
|
1514
|
+
context
|
|
1515
|
+
.blueprint
|
|
1516
|
+
.set(`stone.adapter.errorHandlers.${name}`, { module: errorHandler, isClass: true });
|
|
1517
|
+
});
|
|
1518
|
+
return context;
|
|
1519
1519
|
}
|
|
1520
1520
|
|
|
1521
1521
|
/**
|
|
@@ -1715,16 +1715,26 @@ const StoneClient = ({ children }) => {
|
|
|
1715
1715
|
/**
|
|
1716
1716
|
* Internal link component using Stone.js router.
|
|
1717
1717
|
*/
|
|
1718
|
-
const
|
|
1718
|
+
const StoneLink = ({ to, href, noRel, external, children, ariaCurrentValue = 'page', selectedClass = 'selected', ...rest }) => {
|
|
1719
|
+
const isExternal = external === true;
|
|
1720
|
+
const shouldHandleNav = !isExternal && isNotEmpty(to);
|
|
1719
1721
|
const router = useContext(StoneContext).container.resolve(Router);
|
|
1720
|
-
const path =
|
|
1722
|
+
const path = useMemo(() => {
|
|
1723
|
+
return isObjectLikeModule(to) ? router.generate(to) : to ?? href ?? '#';
|
|
1724
|
+
}, [to, href, router]);
|
|
1721
1725
|
const [currentRoute, setCurrentRoute] = useState(router.getCurrentRoute());
|
|
1722
1726
|
const selectedClassName = currentRoute?.path === path ? selectedClass : undefined;
|
|
1723
|
-
const elemClassName = [className, selectedClassName].filter(Boolean).join(' ').trim();
|
|
1727
|
+
const elemClassName = [rest.className, selectedClassName].filter(Boolean).join(' ').trim();
|
|
1724
1728
|
const handleClick = (event) => {
|
|
1729
|
+
rest.onClick?.(event);
|
|
1730
|
+
if (event.defaultPrevented || isExternal)
|
|
1731
|
+
return;
|
|
1725
1732
|
event.preventDefault();
|
|
1726
|
-
router.navigate(to
|
|
1733
|
+
isNotEmpty(to) && router.navigate(to);
|
|
1727
1734
|
};
|
|
1735
|
+
if (isEmpty(to) && isEmpty(href)) {
|
|
1736
|
+
Logger.warn('StoneLink: missing "to" or "href"');
|
|
1737
|
+
}
|
|
1728
1738
|
useEffect(() => {
|
|
1729
1739
|
const routerEventHandler = (event) => {
|
|
1730
1740
|
setCurrentRoute(event.get('route'));
|
|
@@ -1734,19 +1744,13 @@ const InternalLink = ({ to, href, noRel, children, className, defaultNav, select
|
|
|
1734
1744
|
router.off(RouteEvent.ROUTED, routerEventHandler);
|
|
1735
1745
|
};
|
|
1736
1746
|
}, [router]);
|
|
1737
|
-
return
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
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 }));
|
|
1745
|
-
/**
|
|
1746
|
-
* Main StoneLink component delegating to internal or external versions.
|
|
1747
|
-
*/
|
|
1748
|
-
const StoneLink = (props) => {
|
|
1749
|
-
return props.external === true ? jsx(ExternalLink, { ...props }) : jsx(InternalLink, { ...props });
|
|
1747
|
+
return (
|
|
1748
|
+
// eslint-disable-next-line react/jsx-no-target-blank
|
|
1749
|
+
jsx("a", { ...rest, href: path, className: elemClassName, target: isExternal ? '_blank' : rest.target, "aria-current": isNotEmpty(selectedClassName) ? ariaCurrentValue : undefined, rel: noRel === true
|
|
1750
|
+
? undefined
|
|
1751
|
+
: isExternal
|
|
1752
|
+
? 'noopener noreferrer'
|
|
1753
|
+
: rest.rel, onClick: shouldHandleNav ? handleClick : rest.onClick, children: children }));
|
|
1750
1754
|
};
|
|
1751
1755
|
|
|
1752
1756
|
/**
|
|
@@ -1761,7 +1765,7 @@ const StoneLink = (props) => {
|
|
|
1761
1765
|
* @param options - The options to create the Stone Outlet.
|
|
1762
1766
|
* @returns The Stone Outlet component.
|
|
1763
1767
|
*/
|
|
1764
|
-
const StoneOutlet = ({ children }) => {
|
|
1768
|
+
const StoneOutlet = ({ children, ...rest }) => {
|
|
1765
1769
|
const [currentView, setCurrentView] = useState(children);
|
|
1766
1770
|
useEffect(() => {
|
|
1767
1771
|
const eventName = STONE_PAGE_EVENT_OUTLET;
|
|
@@ -1773,7 +1777,7 @@ const StoneOutlet = ({ children }) => {
|
|
|
1773
1777
|
window.addEventListener(eventName, handleEvent);
|
|
1774
1778
|
return () => window.removeEventListener(eventName, handleEvent);
|
|
1775
1779
|
}, []);
|
|
1776
|
-
return jsx("div", { "data-stone-outlet": 'true', children: currentView });
|
|
1780
|
+
return jsx("div", { ...rest, "data-stone-outlet": 'true', children: currentView });
|
|
1777
1781
|
};
|
|
1778
1782
|
|
|
1779
1783
|
/**
|