@colisweb/rescript-toolkit 2.63.0 → 2.64.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@colisweb/rescript-toolkit",
3
- "version": "2.63.0",
3
+ "version": "2.64.0",
4
4
  "scripts": {
5
5
  "clean": "rescript clean",
6
6
  "build": "rescript build -with-deps",
@@ -57,8 +57,23 @@ module Make = (Config: RouterConfig) => {
57
57
 
58
58
  let useRoute = (): Config.t => RescriptReactRouter.useUrl()->Config.make
59
59
 
60
- let isRouteEqual = (routeA: Config.t, routeB: Config.t): bool =>
61
- routeA->Config.toString === routeB->Config.toString
60
+ let isRouteEqual = (routeA: Config.t, routeB: Config.t): bool => {
61
+ let routeA = {
62
+ let url = routeA->Config.toString
63
+ let queryParamsIndex = url->Js.String2.indexOf("?")
64
+
65
+ queryParamsIndex === -1 ? url : url->Js.String2.slice(~from=0, ~to_=queryParamsIndex)
66
+ }
67
+
68
+ let routeB = {
69
+ let url = routeB->Config.toString
70
+ let queryParamsIndex = url->Js.String2.indexOf("?")
71
+
72
+ queryParamsIndex === -1 ? url : url->Js.String2.slice(~from=0, ~to_=queryParamsIndex)
73
+ }
74
+
75
+ routeA === routeB
76
+ }
62
77
 
63
78
  let useIsCurrentRoute = (route: Config.t): bool => {
64
79
  let {currentRoute} = React.useContext(routerContext)
@@ -71,6 +86,40 @@ module Make = (Config: RouterConfig) => {
71
86
 
72
87
  let toString = Config.toString
73
88
 
89
+ module Breadcrumb = {
90
+ type link = {
91
+ route: Config.t,
92
+ text: React.element,
93
+ }
94
+ type state = {links: option<array<link>>}
95
+
96
+ type action =
97
+ | Reset
98
+ | Update(array<link>)
99
+
100
+ let store = Restorative.createStore({links: None}, (_state, action) =>
101
+ switch action {
102
+ | Reset => {links: None}
103
+ | Update(links) => {links: Some(links)}
104
+ }
105
+ )
106
+
107
+ let use = (routes: array<link>) => {
108
+ React.useLayoutEffect0(() => {
109
+ store.dispatch(Update(routes))
110
+
111
+ Some(() => store.dispatch(Reset))
112
+ })
113
+ }
114
+ }
115
+
116
+ let usePreviousLinkWithDefault = (defaultRoute, cb) => {
117
+ let {previousRoute} = React.useContext(routerContext)
118
+ previousRoute->Option.mapWithDefault(defaultRoute, route => {
119
+ cb(route) ? route : defaultRoute
120
+ })
121
+ }
122
+
74
123
  module Link = {
75
124
  @react.component
76
125
  let make = (
@@ -170,7 +219,13 @@ module Make = (Config: RouterConfig) => {
170
219
 
171
220
  module SingleLink = {
172
221
  @react.component
173
- let make = (~link: link, ~isNavOpen: bool, ~isSubLink=false, ~onLinkClick=() => ()) =>
222
+ let make = (
223
+ ~link: link,
224
+ ~isNavOpen: bool,
225
+ ~isSubLink=false,
226
+ ~isActive=false,
227
+ ~onLinkClick=() => (),
228
+ ) =>
174
229
  switch link {
175
230
  | Legacy({icon, label, url}) =>
176
231
  <a
@@ -198,7 +253,12 @@ module Make = (Config: RouterConfig) => {
198
253
  | App({icon, label, route}) =>
199
254
  <Link
200
255
  route
201
- className={cx([commonClassName, isSubLink ? "ml-3" : "", "sidenav-link"])}
256
+ className={cx([
257
+ commonClassName,
258
+ isSubLink ? "ml-3" : "",
259
+ "sidenav-link",
260
+ isActive ? "bg-primary-100/75 text-neutral-700" : "",
261
+ ])}
202
262
  activeClassName="bg-primary-100/75 text-neutral-700"
203
263
  onClick={_ => onLinkClick()}>
204
264
  <span className="overflow-hidden flex">
@@ -240,6 +300,17 @@ module Make = (Config: RouterConfig) => {
240
300
  | App({route}) => isRouteEqual(currentRoute, route)
241
301
  }
242
302
  })
303
+ let breadcrumb = Breadcrumb.store.useStore()
304
+
305
+ let relativeRoute = breadcrumb.links->Option.mapWithDefault(None, breadcrumbLinks => {
306
+ links->Array.getBy(link => {
307
+ switch link {
308
+ | Legacy(_) => false
309
+ | App({route}) =>
310
+ breadcrumbLinks->Array.some(breadcrumbLink => breadcrumbLink.route->isRouteEqual(route))
311
+ }
312
+ })
313
+ })
243
314
 
244
315
  React.useEffect1(() => {
245
316
  if !isNavOpen {
@@ -257,11 +328,7 @@ module Make = (Config: RouterConfig) => {
257
328
  className={cx([
258
329
  commonClassName,
259
330
  "flex items-center w-full sidenav-link",
260
- switch (hasActiveSubRoute, isNavOpen) {
261
- | (true, true) => "bg-primary-100/50"
262
- | (true, false) => "bg-primary-100/75"
263
- | (false, _) => ""
264
- },
331
+ hasActiveSubRoute || relativeRoute->Option.isSome ? "bg-primary-100/75" : "",
265
332
  ])}>
266
333
  <span className={cx(["mr-2 text-neutral-800", isNavOpen ? "pl-2" : "px-2"])}>
267
334
  groupInfo.icon
@@ -295,11 +362,21 @@ module Make = (Config: RouterConfig) => {
295
362
  isOpen ? "h-auto" : "h-0 overflow-hidden",
296
363
  ])}>
297
364
  {links
298
- ->Array.mapWithIndex((i, link) =>
365
+ ->Array.mapWithIndex((i, link) => {
366
+ let isActive = switch (relativeRoute, link) {
367
+ | (Some(App({route: relativeRoute})), App({route})) =>
368
+ relativeRoute->isRouteEqual(route)
369
+ | _ => false
370
+ }
299
371
  <SingleLink
300
- key={"sidenav-grouped-" ++ i->Int.toString} link isNavOpen isSubLink=true onLinkClick
372
+ key={"sidenav-grouped-" ++ i->Int.toString}
373
+ link
374
+ isNavOpen
375
+ isSubLink=true
376
+ onLinkClick
377
+ isActive
301
378
  />
302
- )
379
+ })
303
380
  ->React.array}
304
381
  </div>
305
382
  </>