{"_id":"@cars4ever/conditional-router","name":"@cars4ever/conditional-router","dist-tags":{"latest":"1.0.20"},"versions":{"1.0.20":{"name":"@cars4ever/conditional-router","version":"1.0.20","description":"Allows to setup conditional routing, multi-domain emulation","author":{"name":"Denis Oborskiy"},"license":"MIT","module":"dist/index.js","main":"dist/index.js","jsnext:main":"dist/index.js","types":"dist/","engines":{"node":">=24"},"scripts":{"start":"yarn clean && NODE_ENV=development rollup -c -w","test":"jest","test:watch":"jest --watchAll","build":"yarn clean && NODE_ENV=production rollup -c","clean":"rimraf dist css .rpt2_cache","lint":"eslint src --ext .ts,.tsx","release:patch":"yarn build && yarn publish --new-version patch","release:minor":"yarn build && yarn publish --new-version minor","release:major":"yarn build && yarn publish --new-version major"},"devDependencies":{"@rollup/plugin-commonjs":"^28.0.0","@rollup/plugin-node-resolve":"^15.0.0","@types/jest":"^29.5.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","@typescript-eslint/eslint-plugin":"^8.0.0","@typescript-eslint/parser":"^8.0.0","eslint":"^9.0.0","eslint-plugin-react":"^7.37.0","eslint-plugin-react-hooks":"^5.0.0","fs-extra":"^11.0.0","jest":"^29.7.0","prettier":"^3.0.0","react":"^19.0.0","react-dom":"^19.0.0","react-redux":"^9.0.0","redux":"^5.0.0","rimraf":"^6.0.0","rollup":"^4.0.0","rollup-plugin-peer-deps-external":"^2.2.4","rollup-plugin-scss":"^4.0.0","@rollup/plugin-typescript":"^12.0.0","ts-jest":"^29.3.0","tslib":"^2.8.0","typescript":"^5.8.0"},"peerDependencies":{"react":"^19.0.0","react-dom":"^19.0.0","react-redux":"^9.0.0","redux":"^5.0.0"},"dependencies":{"path-to-regexp":"^6.3.0","qs":"^6.13.0"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://bitbucket.org/interdan/conditionalrouter.git"},"keywords":["react","router","routing","route","conditional-router","history"],"_id":"@cars4ever/conditional-router@1.0.20","bugs":{"url":"https://bitbucket.org/interdan/conditionalrouter/issues"},"homepage":"https://bitbucket.org/interdan/conditionalrouter#readme","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-2NmH5RVeDdcPqlCdrTCODn3Y3Z9Qt9K4WyU2dE50sWGrAy9Hopq71S0RRxsoGIDlejbuxKQdIZbkwWIAniqEWA==","shasum":"47e446556a609d2f8d3e931ae4e3945118877805","tarball":"https://registry.npmjs.org/@cars4ever/conditional-router/-/conditional-router-1.0.20.tgz","fileCount":34,"unpackedSize":331763,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIC4Tn+lAzlHV4FgvH/NQ8rQSXVWxCOkNMN7srptQ6aKpAiBOLbFkWjW2lO4IgmtKaO+/b7gh97YivCy4s+Mj+1afWg=="}]},"_npmUser":{"name":"wismogroup_developer","email":"digital@wismogroup.com"},"directories":{},"maintainers":[{"name":"wismogroup_developer","email":"digital@wismogroup.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/conditional-router_1.0.20_1777642599256_0.1105830154320071"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-01T13:36:39.126Z","1.0.20":"2026-05-01T13:36:39.431Z","modified":"2026-05-01T13:36:39.722Z"},"maintainers":[{"name":"wismogroup_developer","email":"digital@wismogroup.com"}],"description":"Allows to setup conditional routing, multi-domain emulation","homepage":"https://bitbucket.org/interdan/conditionalrouter#readme","keywords":["react","router","routing","route","conditional-router","history"],"repository":{"type":"git","url":"git+https://bitbucket.org/interdan/conditionalrouter.git"},"author":{"name":"Denis Oborskiy"},"bugs":{"url":"https://bitbucket.org/interdan/conditionalrouter/issues"},"license":"MIT","readme":"# Conditional react/redux router\n\nLibrary allows to setup routing for React-Redux application. Main features:\n\n* clean and simple setup with pure JavaScript (TypeScript)\n\n* every route rule allows to perform checks and, if necessary, redirection: you don't need <Redirect ... /> inside your components\n\n* when some route is applied you can access redux state, routing parameters and dispatch before your component even start mounting; so when a component is being connected to store - you can be sure all the selectors have returned the correct values (based on your current route and routing parameters)\n\n* with `requiredStep` and `routesToLockOnFirstLoad` options performs auto-redirection back and forward in your business flow\n\n* supports multi-domains simulation: drastically simplify your development when you are building the solution that will be published with several different domain names; on your single localhost you can jump across all your domains and see how the solution will behave with real domain names\n\n* minor dependencies: `path-to-regexp` and `qs` only; also require you to pass history object (the most popular choise is to use `history` npm package)\n\n## Installation\n    npm install @cars4ever/conditional-router\n\n## Peer dependencies\nLibrary expects your app is using react with redux, it's a list of peer dependencies:\n\n* react, react-dom: ^16.7.0\n\n* redux - ^4.0.1, react-redux - ^6.0.0\n\nThe best way to get the filing how it works - looks at the example app in git repository.\n\n## Simple example\n\nCreating a history object in separate file (to support hot module replacement):\n\n```javascript\nimport { createBrowserHistory } from 'history';\nexport default createBrowserHistory();\n```\n\nYour app component is fairly simple:\n\n```jsx\nimport React from 'react';\nimport { Provider } from 'react-redux';\nimport history from './sharedHistory';\nimport { ConditionalRouter } from '@cars4ever/conditional-router';\nimport store from '<your redux store path>/store';\nimport setRoutingRules from './routingRules';\n\nconst App = () => (\n  <Provider store={store}>\n    <ConditionalRouter setRules={setRoutingRules} history={history} />\n  </Provider>\n);\n```\n\nYour routing rules file - (routingRules.js or routingRules.ts):\n\n```javascript\nimport StartView from './components/StartView';\nimport AboutUs from './components/AboutUs';\nimport Contacts from './components/Contacts';\n\nexport default function setRoutingRules(addRoutes, navigator) {\n  addRoutes([\n    {\n      StartView,\n      path: '/',\n      useAsDefault: true,\n    },\n\n    { AboutUs },\n\n    { Contacts },\n  ]);\n}\n```\n\nThere is several options for navigation inside your components:\n\n* use button and handle click with method `go` of `navigator` object\n\n* use NavLink and pass there added navigator's route value\n\n* use NavLink and pass there strings like `/`, `/AboutUs`, `/Contacts`\n\n* in some other cases where we need a URL, we can get it just by `url` property of `navigator` object\n\nIn general, `navigator.<RouteName>([optional parameters values])` returns `UrlProvider` object with two fields: `url` string property, and parameterless `go()` method.\n\nExample shows how it works:\n\n```jsx\nimport React from 'react';\nimport navigator, { NavLink } from '@cars4ever/conditional-router';\n\nconst StartView = () => {\n  const contactsUrl = navigator.Contacts().url;\n  console.log(contactsUrl === '/Contacts'); // true\n\n  return (\n    <div className={start-view}>\n      <h1>It is a test main page of our app</h1>\n      Read \"<NavLink to={navigator.AboutUs()}>about us</NavLink>\" page.\n      <NavLink to={navigator.AboutUs}>This link</NavLink> will also open \"about us\" page.\n      Our contact information is available by <NavLink to=\"/Contacts\">this link</NavLink>.\n\n      Also you can reach the contacts page by clicking\n      <button onClick={navigator.Contacts().go}>this button</button>\n    </div>\n  );\n};\n\n...\n\n```\n## `addRoutes` function parameters\n\n`addRoutes` it's a base function you will use to setup router with this library.\n\nThe first, second and all the next parameters except the last one are must be React components that you can use as a parent container.\nLet's say, you have such JSX:\n\n```jsx\n<BrandContainer>\n  <AboutUs />\n  <Contacts />\n</BrandContainer>\n```\n\nAnd you want to define the routes for this `AboutUs` and `Contacts` pages. You must put `BrandContainer` before the route rules:\n\n```javascript\naddRoutes(BrandContainer, [\n  { AboutUs },\n  { Contacts },\n]);\n```\n\nLast parameter passed to `addRoutes` function should be your route rule or an array of such rules. Two examples below create the same setup:\n\n```javascript\n  addRoutes(BrandContainer, {\n    StartView,\n    path: '/',\n    useAsDefault: true,\n  });\n\n  addRoutes(BrandContainer, { AboutUs });\n  addRoutes(BrandContainer, { Contacts });\n```\n\nis the same as\n\n```javascript\naddRoutes(BrandContainer, [\n  {\n    StartView,\n    path: '/',\n    useAsDefault: true,\n  },\n\n  { AboutUs },\n\n  { Contacts },\n]);\n```\n\n## Route parameters\n\n* Required React component property - as you can guess from the example above, there are no other required parameters, except this one:\n\n```javascript\nexport default function setRoutingRules(addRoutes, navigator) {\n  addRoutes([\n    ...\n\n    { Contacts },\n\n    ...\n  ]);\n}\n```\n\nSo this component is the only required property of the route rule object. Moreover, it can have any name, but the name must be stylized with Pascal case - the First letter should be in up case. Since all the other parameter names start with a lower case letter, it's possible to figure out where the component. The expected type of this parameter - a function or object (for memoized React components). This name also used to refer to this route using the navigator object: `navigator.Contacts().url`.\n\n* `path` property - allows you to override the default path name for this route or add parameters to your URL. The default value for `path` is `/<Your component name>`. So for example above `path === '/Contacts'`\n\nTo add `path` with parameters use colon with this format:\n\n```jsx\n{ Contacts, path: `/Contacts/:country?cityName=:city` },\n```\n\nParameters that are part of the path name are required, but query parameters are optional.\n\n```jsx\n{ Contacts, path: `/Contacts/:country?cityName=:city` },\n\n...\n\n// next line will print: \"url: /Contacts/Canada?cityName=Vancouver\"\nconsole.log('url: ', navigator.Contacts({ country: 'Canada', city: 'Vancouver' }).url);\n\n...\n\n<button onClick={navigator.Contacts({ country: 'Canada', city: 'Vancouver' }).go}>this button</button>\n```\n\n* `beforeRoute` - is a function that accepts getState as a single parameter,\n  must return another function that accepts an object - current URL match parameters.\n  This function can return another route to perform the redirection or anything else to do nothing.\n\nExample:\n\n```javascript\naddRoute({\n  Contacts,\n  path: `/Contacts/:country?cityName=:city`,\n  beforeRoute: getState => ({ country, city }) => {\n      return !getState().session.isAuthorized && country === 'Oz' ? navigator.DontPlayWithUsPage : null;\n    }\n  },\n});\n```\n\n* `onRoute` - is a function that accepts two parameters: dispatch and getState,\n  must return another function that accepts an object - current URL match parameters.\n  This parameter can be used to dispatch actions once route applied but before mounting the corresponding component:\n\n```javascript\naddRoute({\n  Contacts,\n  path: `/Contacts/:country?cityName=:city`,\n  onRoute: (dispatch, getState) => ({ country, city }) => {\n    if (getState().session.isAuthorized) {\n      dispatch({ type: 'SET_CITY', payload: { country, city } });\n    }\n  },\n});\n```\n\n* `useAsDefault` (boolean parameter) - if true - sets that this route should be used for redirection\n  when provided URL isn't valid. It could be 404 page, home page, etc.\n  This parameter should be used only once per application, otherwise the exception will be thrown\n\n* `requiredStep` (boolean parameter) - if true - sets that this route is a part of the business workflow\n  and it can't be skipped. The route added after this one will be checked that this route was visited,\n  otherwise the redirected to this route will take place.\n  First route always has true value as default for this parameter.\n\nExample:\n\n```javascript\naddRoute([\n  {\n    StartView,\n    path: '/',\n    useAsDefault: true,\n    requiredStep: true,\n  },\n\n  { AboutUs, requiredStep: true },\n\n  { Contacts },\n]);\n```\n\n  Then if user enter the URL in browser like *my-site.com/Contacts* without visiting\n  *my-site.com/AboutUs* page he will be redirected to *my-site.com/AboutUs*\n  or to *my-site.com* if he haven't visit start page either\n\n* `routesToLockOnFirstLoad` - an object with keys that are related to already added routes that will be locked for second visit when this route is applied:\n\nExample:\n\n```javascript\naddRoute([\n  ...\n  {\n    Checkout,\n    requiredStep: true,\n  },\n  {\n    CongratulationPage,\n    routesToLockOnFirstLoad: { Checkout, WirelessChargingChooser, WaterProtectionChooser, ... },\n  },\n]);\n```\n\nWhen a user reaches `CongratulationPage` he can't go back to Checkout, WirelessChargingChooser, WaterProtectionChooser and other locked routes.\n\n* `alwaysAccessibleRoute` - (boolean parameter) - if true all routing rules for other routes like `requiredStep`, `routesToLockOnFirstLoad` are ignored. The only possible redirection - if it set for the current rule with `beforeRoute` option. This option designed to simplify adding routes for general views: FAQ, Support, etc.\n\n* `customSettings` - an object that will be passed to the global `onRoute` handler:\n\n```jsx\naddRoute([\n  ...\n  {\n    Checkout,\n    customSettings: { syncSession: true },\n    requiredStep: true,\n  },\n  {\n    CongratulationPage,\n    customSettings: { syncSession: true },\n    routesToLockOnFirstLoad: { Checkout, WirelessChargingChooser, WaterProtectionChooser, ResolutionChooser },\n  },\n]);\n\n...\n\n// 'dispatch' & 'getState' aren't used here, but you can get state value and dispatch actions\n// 'routeParams' is also available here\nconst onRouteGlobalHandler = (dispatch, getState) =>\n  (routeParams, routeCustomSettings) => {\n    if (routeCustomSettings && routeCustomSettings.syncSession) {\n      console.log('sync session');\n    }\n  };\n\n...\n\n<ConditionalRouter\n  onRoute={onRouteGlobalHandler}\n  ...\n/>\n\n```\n\n* `skipWhenBackToPrevious` - boolean parameter, equals `false` by default. Notify that specifit route must be skipped when `navigator.navigateToPreviousRoute()` method used\n\n* `domainName` - string parameter - make sense for multi-domains mode only, empty string or last provided `domainName` value in rules above. Bind specific route to specific domain name since it's possible to have several routes with the same route name like \"Contacts\", \"AboutUs\", etc.\n\n## Multi-domains mode\n\nIn this mode, your app with absolutely the same source code can be bound to different domain names. But for the local host, it will behave the same way as for real. Instead of different domain names, the router just adds `domainName` query parameters for all the URL and resolves them dynamically based on route rules and the current domain name. In this mode `ConditionalRouter` expects three more required parameter: `isMultiDomainEmulating`, `useHttpsForMultiDomainsApp` and `switchStateActionCreator`:\n\n```jsx\nconst isMultiDomainEmulating = isDevelopEnv || isStageEnv;\n\nfunction switchStateActionCreator(domainName) {\n  return {\n    type: actionTypes.RESTORE_STATE,\n    payload: restoreStateFromLocalStorage(domainName),\n  };\n}\n...\n\n <ConditionalRouter\n  isMultiDomainEmulating={isMultiDomainEmulating}\n  useHttpsForMultiDomainsApp={isProduction || isStageEnv}\n  switchStateActionCreator={switchStateActionCreator}\n\n  setRules={setRoutingRules}\n  history={history}\n/>\n```\n\nIt's not required for all cases buts it's a good practice to set `domainName` for all the route rules:\n\n```javascript\nexport default function setRoutingRules(addRoutes: TAddRoutesType, navigator: any) {\n\n  setMainDomainRoutingRules(addRoutes, navigator);\n\n  commonFlowDomains.forEach((domainName: string) => {\n    addRoutes(BrandContainer, [\n      {\n        domainName,\n        ResolutionChooser,\n        ...\n      },\n      { WaterProtectionChooser, domainName, skipWhenBackToPrevious: true },\n      {\n        WirelessChargingChooser,\n        domainName,\n        ...\n      },\n    ]);\n  });\n}\n```","readmeFilename":"README.md","_rev":"1-6530b0ad00f2a2a898e72e60f3687d1f"}