@alexandregme/zljs 1.15.0 → 1.17.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/CHANGELOG.md CHANGED
@@ -8,6 +8,37 @@ A change that needs action in an app has a **Migration** note. When updating, re
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.17.0] - 2026-11-02
12
+
13
+ ### Added
14
+
15
+ - `ReduxProvider`, the new name of `GlobalState`, with the types `ReduxProviderProps` and `ReduxStore`. It behaves the same
16
+
17
+ ### Removed
18
+
19
+ - `GlobalState`, `GlobalStateProps` and `ExtendedStore`
20
+
21
+ #### Migration
22
+
23
+ Search the app for `GlobalState`, `GlobalStateProps` and `ExtendedStore` imported from `@alexandregme/zljs`, and replace them with `ReduxProvider`, `ReduxProviderProps` and `ReduxStore`. The props don't change.
24
+
25
+ ## [1.16.0] - 2026-11-02
26
+
27
+ ### Added
28
+
29
+ - `Link` in `@alexandregme/zljs/next`: navigates with `next/link` and takes `children`, `href` and `color`, with the `SemanticColor` values. It is always underlined, inherits the font size around it and has a 44px touch target, so keep at least 20px between stacked links
30
+ - `NotFound` takes `backLabel`. "Go back home" was fixed, so an app in another language couldn't translate it
31
+
32
+ ### Changed
33
+
34
+ - `RootLayout` takes the height of the visible screen, with `min-h-dvh` instead of `min-h-screen`, so it doesn't scroll on a phone
35
+ - `NotFound` is built with `Heading`, `Text` and `Link`: the title goes from `text-2xl` semibold to `text-3xl` bold, the message uses the theme's `muted`, and the link follows the theme and is always underlined. It navigates with `next/link` instead of reloading the page
36
+ - `NotFound` takes the height of the visible screen, with `min-h-dvh` instead of `min-h-screen`, so it doesn't scroll on a phone
37
+
38
+ ### Fixed
39
+
40
+ - The `404` of `NotFound` had 1.47:1 contrast on white with `text-gray-300`. It now uses the theme's `muted`, which is 4.84:1
41
+
11
42
  ## [1.15.0] - 2026-11-02
12
43
 
13
44
  ### Added
@@ -190,7 +221,9 @@ Replace the shade with the class of the `color` being tested, for example `/(^|\
190
221
 
191
222
  The message of `Error` is `text-zl-danger`. `none` and `ghost` didn't change.
192
223
 
193
- [Unreleased]: https://github.com/alexandregme/zljs/compare/v1.15.0...HEAD
224
+ [Unreleased]: https://github.com/alexandregme/zljs/compare/v1.17.0...HEAD
225
+ [1.17.0]: https://github.com/alexandregme/zljs/compare/v1.16.0...v1.17.0
226
+ [1.16.0]: https://github.com/alexandregme/zljs/compare/v1.15.0...v1.16.0
194
227
  [1.15.0]: https://github.com/alexandregme/zljs/compare/v1.14.0...v1.15.0
195
228
  [1.14.0]: https://github.com/alexandregme/zljs/compare/v1.13.0...v1.14.0
196
229
  [1.13.0]: https://github.com/alexandregme/zljs/compare/v1.12.0...v1.13.0
@@ -0,0 +1,83 @@
1
+ "use client";
2
+
3
+ // core/text/text.styles.ts
4
+ import { tv } from "tailwind-variants";
5
+
6
+ // core/types/colors/colors.const.ts
7
+ var semanticTextColors = {
8
+ primary: "text-zl-primary",
9
+ success: "text-zl-success",
10
+ danger: "text-zl-danger",
11
+ warning: "text-zl-warning",
12
+ info: "text-zl-info",
13
+ muted: "text-zl-muted",
14
+ none: ""
15
+ };
16
+
17
+ // core/text/text.styles.ts
18
+ var text = tv({
19
+ variants: {
20
+ variant: {
21
+ body: "text-base",
22
+ caption: "text-sm",
23
+ display: "text-3xl font-bold"
24
+ },
25
+ color: semanticTextColors
26
+ },
27
+ defaultVariants: {
28
+ variant: "body"
29
+ }
30
+ });
31
+
32
+ // core/text/text.tsx
33
+ import { jsx } from "react/jsx-runtime";
34
+ var Text = ({
35
+ children,
36
+ as: Tag = "p",
37
+ variant = "body",
38
+ color
39
+ }) => {
40
+ return /* @__PURE__ */ jsx(Tag, { "data-testid": "text", className: text({ variant, color }), children });
41
+ };
42
+
43
+ // core/heading/heading.const.ts
44
+ var headingTags = {
45
+ 1: "h1",
46
+ 2: "h2",
47
+ 3: "h3",
48
+ 4: "h4",
49
+ 5: "h5",
50
+ 6: "h6"
51
+ };
52
+
53
+ // core/heading/heading.styles.ts
54
+ import { tv as tv2 } from "tailwind-variants";
55
+ var heading = tv2({
56
+ variants: {
57
+ level: {
58
+ 1: "text-3xl font-bold",
59
+ 2: "text-2xl font-bold",
60
+ 3: "text-xl font-semibold",
61
+ 4: "text-lg font-semibold",
62
+ 5: "text-base font-medium",
63
+ 6: "text-sm font-medium"
64
+ },
65
+ color: semanticTextColors
66
+ },
67
+ defaultVariants: {
68
+ level: 1
69
+ }
70
+ });
71
+
72
+ // core/heading/heading.tsx
73
+ import { jsx as jsx2 } from "react/jsx-runtime";
74
+ var Heading = ({ children, level = 1, color }) => {
75
+ const Tag = headingTags[level];
76
+ return /* @__PURE__ */ jsx2(Tag, { className: heading({ level, color }), children });
77
+ };
78
+
79
+ export {
80
+ semanticTextColors,
81
+ Text,
82
+ Heading
83
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Semantic colors for action-oriented components (Button, Heading, etc.)
3
+ */
4
+ type SemanticColor = "primary" | "success" | "danger" | "warning" | "info" | "muted" | "none";
5
+ /**
6
+ * Literal colors for data visualization components (StatsCard, etc.)
7
+ */
8
+ type DataColor = "blue" | "red" | "yellow" | "green" | "gray" | "orange";
9
+
10
+ export type { DataColor as D, SemanticColor as S };
package/dist/index.d.ts CHANGED
@@ -1,20 +1,12 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ChangeEvent, FormEvent, HTMLInputAutoCompleteAttribute, FocusEvent, KeyboardEvent, Ref } from 'react';
3
+ import { S as SemanticColor, D as DataColor } from './colors-CvgrDPVc.js';
3
4
  export { FormInput, FormInputProps, FormProvider, FormProviderProps } from './rhf/index.js';
4
5
  export { toast } from 'sonner';
5
6
  import * as zustand from 'zustand';
6
- import { Store, Reducer, Middleware, Dispatch } from '@reduxjs/toolkit';
7
+ import { Reducer, Middleware, Store, Dispatch } from '@reduxjs/toolkit';
7
8
  import 'react-hook-form';
8
9
 
9
- /**
10
- * Semantic colors for action-oriented components (Button, Heading, etc.)
11
- */
12
- type SemanticColor = "primary" | "success" | "danger" | "warning" | "info" | "muted" | "none";
13
- /**
14
- * Literal colors for data visualization components (StatsCard, etc.)
15
- */
16
- type DataColor = "blue" | "red" | "yellow" | "green" | "gray" | "orange";
17
-
18
10
  /**
19
11
  * Sizes shared by every sized component (Icon, Button, Input, etc.)
20
12
  */
@@ -370,10 +362,7 @@ declare const useModalStore: zustand.UseBoundStore<Omit<zustand.StoreApi<ModalSt
370
362
  };
371
363
  }>;
372
364
 
373
- interface ExtendedStore extends Store {
374
- setDynamicReducers?: (reducers: Record<string, Reducer>) => void;
375
- }
376
- interface GlobalStateProps {
365
+ interface ReduxProviderProps {
377
366
  children: ReactNode;
378
367
  reducers?: Record<string, Reducer>;
379
368
  middlewares?: Middleware[];
@@ -381,7 +370,11 @@ interface GlobalStateProps {
381
370
  coreReducers?: Record<string, Reducer>;
382
371
  }
383
372
 
384
- declare const GlobalState: ({ children, reducers, middlewares, preloadedState, coreReducers, }: GlobalStateProps) => react.JSX.Element;
373
+ declare const ReduxProvider: ({ children, reducers, middlewares, preloadedState, coreReducers, }: ReduxProviderProps) => react.JSX.Element;
374
+
375
+ interface ReduxStore extends Store {
376
+ setDynamicReducers?: (reducers: Record<string, Reducer>) => void;
377
+ }
385
378
 
386
379
  interface RouterState {
387
380
  urlAsPath: string;
@@ -506,5 +499,5 @@ declare class HTTPClient {
506
499
  patch<T = unknown>(url: string, config?: HttpRequestConfig): Promise<T | undefined>;
507
500
  }
508
501
 
509
- export { AppWrapper, Button, Checkbox, ConnectedModal, DataGrid, DocumentWrapper, Error, Form, GlobalState, HTTPClient, Heading, Icon, Input, Loader, Modal, PageWrapper, Radio, Select, Sidebar, Spinner, StatsCard, Tag, Text, TextArea, Toaster, WhatsAppButton, splitURLasPath, useAppStore, useModalStore, usePageStore, useRouterStore, useToastStore };
510
- export type { AppState, AppWrapperProps, ButtonColor, ButtonProps, ButtonVariant, CheckboxProps, CheckboxVariant, ConnectedModalProps, DataColor, DataGridColumn, DataGridProps, DocumentWrapperProps, ErrorProps, ExtendedStore, FormProps, GlobalStateProps, HeadingProps, HttpClientConfig, HttpRequestConfig, IconName, IconProps, InitPageFunction, InputProps, LoaderProps, ModalEntry, ModalProps, ModalState, PageState, PageWrapperProps, RadioProps, RouterState, SelectOption, SelectProps, SemanticColor, SidebarItem, SidebarProps, SidebarSection, SidebarUser, Size, SpinnerProps, SpinnerVariant, StatsCardProps, TagProps, TextAreaProps, TextProps, TextVariant, Toast, ToastState, ToastType, WhatsAppButtonProps };
502
+ export { AppWrapper, Button, Checkbox, ConnectedModal, DataColor, DataGrid, DocumentWrapper, Error, Form, HTTPClient, Heading, Icon, Input, Loader, Modal, PageWrapper, Radio, ReduxProvider, Select, SemanticColor, Sidebar, Spinner, StatsCard, Tag, Text, TextArea, Toaster, WhatsAppButton, splitURLasPath, useAppStore, useModalStore, usePageStore, useRouterStore, useToastStore };
503
+ export type { AppState, AppWrapperProps, ButtonColor, ButtonProps, ButtonVariant, CheckboxProps, CheckboxVariant, ConnectedModalProps, DataGridColumn, DataGridProps, DocumentWrapperProps, ErrorProps, FormProps, HeadingProps, HttpClientConfig, HttpRequestConfig, IconName, IconProps, InitPageFunction, InputProps, LoaderProps, ModalEntry, ModalProps, ModalState, PageState, PageWrapperProps, RadioProps, ReduxProviderProps, ReduxStore, RouterState, SelectOption, SelectProps, SidebarItem, SidebarProps, SidebarSection, SidebarUser, Size, SpinnerProps, SpinnerVariant, StatsCardProps, TagProps, TextAreaProps, TextProps, TextVariant, Toast, ToastState, ToastType, WhatsAppButtonProps };
package/dist/index.js CHANGED
@@ -1,4 +1,9 @@
1
1
  "use client";
2
+ import {
3
+ Heading,
4
+ Text,
5
+ semanticTextColors
6
+ } from "./chunk-CXA5QIHP.js";
2
7
  import {
3
8
  Error,
4
9
  FormInput,
@@ -25,19 +30,6 @@ var iconSizes = {
25
30
 
26
31
  // core/icon/icon.styles.ts
27
32
  import { tv } from "tailwind-variants";
28
-
29
- // core/types/colors/colors.const.ts
30
- var semanticTextColors = {
31
- primary: "text-zl-primary",
32
- success: "text-zl-success",
33
- danger: "text-zl-danger",
34
- warning: "text-zl-warning",
35
- info: "text-zl-info",
36
- muted: "text-zl-muted",
37
- none: ""
38
- };
39
-
40
- // core/icon/icon.styles.ts
41
33
  var icon = tv({
42
34
  variants: {
43
35
  color: semanticTextColors
@@ -744,36 +736,9 @@ var DataGrid = ({
744
736
  );
745
737
  };
746
738
 
747
- // core/text/text.styles.ts
748
- import { tv as tv9 } from "tailwind-variants";
749
- var text = tv9({
750
- variants: {
751
- variant: {
752
- body: "text-base",
753
- caption: "text-sm",
754
- display: "text-3xl font-bold"
755
- },
756
- color: semanticTextColors
757
- },
758
- defaultVariants: {
759
- variant: "body"
760
- }
761
- });
762
-
763
- // core/text/text.tsx
764
- import { jsx as jsx12 } from "react/jsx-runtime";
765
- var Text = ({
766
- children,
767
- as: Tag2 = "p",
768
- variant = "body",
769
- color
770
- }) => {
771
- return /* @__PURE__ */ jsx12(Tag2, { "data-testid": "text", className: text({ variant, color }), children });
772
- };
773
-
774
739
  // core/stats-card/stats-card.styles.ts
775
- import { tv as tv10 } from "tailwind-variants";
776
- var statsCard = tv10({
740
+ import { tv as tv9 } from "tailwind-variants";
741
+ var statsCard = tv9({
777
742
  base: "p-4 rounded-lg",
778
743
  variants: {
779
744
  color: {
@@ -788,11 +753,11 @@ var statsCard = tv10({
788
753
  });
789
754
 
790
755
  // core/stats-card/stats-card.tsx
791
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
756
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
792
757
  var StatsCard = ({ label: label5, value, color }) => {
793
758
  return /* @__PURE__ */ jsxs10("div", { "data-testid": "stats-card", className: statsCard({ color }), children: [
794
- /* @__PURE__ */ jsx13(Text, { variant: "caption", children: label5 }),
795
- /* @__PURE__ */ jsx13(Text, { variant: "display", children: value })
759
+ /* @__PURE__ */ jsx12(Text, { variant: "caption", children: label5 }),
760
+ /* @__PURE__ */ jsx12(Text, { variant: "display", children: value })
796
761
  ] });
797
762
  };
798
763
 
@@ -800,11 +765,11 @@ var StatsCard = ({ label: label5, value, color }) => {
800
765
  import * as Dialog from "@radix-ui/react-dialog";
801
766
 
802
767
  // core/modal/modal.styles.ts
803
- import { tv as tv11 } from "tailwind-variants";
804
- var overlay = tv11({
768
+ import { tv as tv10 } from "tailwind-variants";
769
+ var overlay = tv10({
805
770
  base: "fixed inset-0 bg-black/50"
806
771
  });
807
- var content = tv11({
772
+ var content = tv10({
808
773
  base: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-lg shadow-lg p-6 w-full focus:outline-none max-h-[90vh] overflow-y-auto",
809
774
  variants: {
810
775
  size: {
@@ -819,21 +784,21 @@ var content = tv11({
819
784
  size: "md"
820
785
  }
821
786
  });
822
- var header = tv11({
787
+ var header = tv10({
823
788
  base: "flex items-start justify-between"
824
789
  });
825
- var title = tv11({
790
+ var title = tv10({
826
791
  base: "text-lg font-semibold text-gray-900 m-0"
827
792
  });
828
- var description = tv11({
793
+ var description = tv10({
829
794
  base: "text-sm text-gray-600 mt-2"
830
795
  });
831
- var body = tv11({
796
+ var body = tv10({
832
797
  base: "mt-4"
833
798
  });
834
799
 
835
800
  // core/modal/modal.tsx
836
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
801
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
837
802
  var Modal = ({
838
803
  open,
839
804
  onClose,
@@ -842,8 +807,8 @@ var Modal = ({
842
807
  children,
843
808
  size = "md"
844
809
  }) => {
845
- return /* @__PURE__ */ jsx14(Dialog.Root, { open, onOpenChange: (isOpen) => !isOpen && onClose(), children: /* @__PURE__ */ jsxs11(Dialog.Portal, { children: [
846
- /* @__PURE__ */ jsx14(Dialog.Overlay, { className: overlay() }),
810
+ return /* @__PURE__ */ jsx13(Dialog.Root, { open, onOpenChange: (isOpen) => !isOpen && onClose(), children: /* @__PURE__ */ jsxs11(Dialog.Portal, { children: [
811
+ /* @__PURE__ */ jsx13(Dialog.Overlay, { className: overlay() }),
847
812
  /* @__PURE__ */ jsxs11(
848
813
  Dialog.Content,
849
814
  {
@@ -851,11 +816,11 @@ var Modal = ({
851
816
  ...!description2 && { "aria-describedby": void 0 },
852
817
  children: [
853
818
  /* @__PURE__ */ jsxs11("div", { className: header(), children: [
854
- /* @__PURE__ */ jsx14(Dialog.Title, { className: title(), children: title2 }),
855
- /* @__PURE__ */ jsx14(Button, { icon: "X", "aria-label": "Close", onClick: onClose })
819
+ /* @__PURE__ */ jsx13(Dialog.Title, { className: title(), children: title2 }),
820
+ /* @__PURE__ */ jsx13(Button, { icon: "X", "aria-label": "Close", onClick: onClose })
856
821
  ] }),
857
- description2 && /* @__PURE__ */ jsx14(Dialog.Description, { className: description(), children: description2 }),
858
- children && /* @__PURE__ */ jsx14("div", { className: body(), children })
822
+ description2 && /* @__PURE__ */ jsx13(Dialog.Description, { className: description(), children: description2 }),
823
+ children && /* @__PURE__ */ jsx13("div", { className: body(), children })
859
824
  ]
860
825
  }
861
826
  )
@@ -868,7 +833,7 @@ var whatsappBusinessUrl = "whatsapp-business://send";
868
833
  var whatsappMobileUserAgent = /Android|iPhone|iPad|iPod/i;
869
834
 
870
835
  // core/whatsapp-button/whatsapp-button.tsx
871
- import { jsx as jsx15 } from "react/jsx-runtime";
836
+ import { jsx as jsx14 } from "react/jsx-runtime";
872
837
  var WhatsAppButton = ({
873
838
  phone,
874
839
  message,
@@ -893,43 +858,7 @@ var WhatsAppButton = ({
893
858
  }
894
859
  onClick?.();
895
860
  };
896
- return /* @__PURE__ */ jsx15(Button, { color: "success", icon: "SiWhatsapp", onClick: handleClick, children });
897
- };
898
-
899
- // core/heading/heading.const.ts
900
- var headingTags = {
901
- 1: "h1",
902
- 2: "h2",
903
- 3: "h3",
904
- 4: "h4",
905
- 5: "h5",
906
- 6: "h6"
907
- };
908
-
909
- // core/heading/heading.styles.ts
910
- import { tv as tv12 } from "tailwind-variants";
911
- var heading = tv12({
912
- variants: {
913
- level: {
914
- 1: "text-3xl font-bold",
915
- 2: "text-2xl font-bold",
916
- 3: "text-xl font-semibold",
917
- 4: "text-lg font-semibold",
918
- 5: "text-base font-medium",
919
- 6: "text-sm font-medium"
920
- },
921
- color: semanticTextColors
922
- },
923
- defaultVariants: {
924
- level: 1
925
- }
926
- });
927
-
928
- // core/heading/heading.tsx
929
- import { jsx as jsx16 } from "react/jsx-runtime";
930
- var Heading = ({ children, level = 1, color }) => {
931
- const Tag2 = headingTags[level];
932
- return /* @__PURE__ */ jsx16(Tag2, { className: heading({ level, color }), children });
861
+ return /* @__PURE__ */ jsx14(Button, { color: "success", icon: "SiWhatsapp", onClick: handleClick, children });
933
862
  };
934
863
 
935
864
  // core/sidebar/sidebar.tsx
@@ -937,8 +866,8 @@ import { useState as useState3 } from "react";
937
866
  import Link from "next/link.js";
938
867
 
939
868
  // core/sidebar/sidebar.styles.ts
940
- import { tv as tv13 } from "tailwind-variants";
941
- var sidebar = tv13({
869
+ import { tv as tv11 } from "tailwind-variants";
870
+ var sidebar = tv11({
942
871
  base: "h-screen bg-neutral-800 text-neutral-300 flex flex-col overflow-hidden transition-all duration-200",
943
872
  variants: {
944
873
  collapsed: {
@@ -950,16 +879,16 @@ var sidebar = tv13({
950
879
  collapsed: false
951
880
  }
952
881
  });
953
- var nav = tv13({
882
+ var nav = tv11({
954
883
  base: "flex-1 min-h-0 overflow-y-auto overflow-x-hidden"
955
884
  });
956
- var header2 = tv13({
885
+ var header2 = tv11({
957
886
  base: "shrink-0 border-b border-neutral-600/50 grid p-2"
958
887
  });
959
- var section = tv13({
888
+ var section = tv11({
960
889
  base: "border-b border-neutral-600/50 last:border-b-0 grid gap-1 p-2"
961
890
  });
962
- var item = tv13({
891
+ var item = tv11({
963
892
  base: "flex w-full items-center rounded-md text-sm whitespace-nowrap transition-colors cursor-pointer p-1",
964
893
  variants: {
965
894
  active: {
@@ -971,10 +900,10 @@ var item = tv13({
971
900
  active: false
972
901
  }
973
902
  });
974
- var itemIcon = tv13({
903
+ var itemIcon = tv11({
975
904
  base: "p-2"
976
905
  });
977
- var itemLabel = tv13({
906
+ var itemLabel = tv11({
978
907
  base: "truncate transition-all duration-200",
979
908
  variants: {
980
909
  collapsed: {
@@ -986,27 +915,27 @@ var itemLabel = tv13({
986
915
  collapsed: false
987
916
  }
988
917
  });
989
- var footer = tv13({
918
+ var footer = tv11({
990
919
  base: "shrink-0 border-t border-neutral-600/50 p-3 flex items-center gap-3 whitespace-nowrap"
991
920
  });
992
- var avatar = tv13({
921
+ var avatar = tv11({
993
922
  base: "shrink-0 w-8 h-8 rounded-full bg-neutral-600 text-white text-xs font-medium flex items-center justify-center"
994
923
  });
995
- var userInfo = tv13({
924
+ var userInfo = tv11({
996
925
  base: "flex flex-col min-w-0"
997
926
  });
998
- var userName = tv13({
927
+ var userName = tv11({
999
928
  base: "text-sm text-white truncate"
1000
929
  });
1001
- var userEmail = tv13({
930
+ var userEmail = tv11({
1002
931
  base: "text-xs text-neutral-400"
1003
932
  });
1004
- var toggleButton = tv13({
933
+ var toggleButton = tv11({
1005
934
  base: "shrink-0 border-t border-neutral-600/50 grid p-2 [&>button]:justify-start [&>button]:overflow-hidden [&>button]:whitespace-nowrap"
1006
935
  });
1007
936
 
1008
937
  // core/sidebar/sidebar.tsx
1009
- import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
938
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1010
939
  var getInitials = (name) => {
1011
940
  const parts = name.trim().split(/\s+/);
1012
941
  if (parts.length >= 2) {
@@ -1027,19 +956,19 @@ var Sidebar = ({
1027
956
  const [collapsed, setCollapsed] = useState3(defaultCollapsed);
1028
957
  const initials = getInitials(user.name);
1029
958
  return /* @__PURE__ */ jsxs12("aside", { className: sidebar({ collapsed }), children: [
1030
- homeHref && /* @__PURE__ */ jsx17(
959
+ homeHref && /* @__PURE__ */ jsx15(
1031
960
  Link,
1032
961
  {
1033
962
  href: homeHref,
1034
963
  className: header2(),
1035
964
  "aria-label": homeLabel || "Home",
1036
965
  children: /* @__PURE__ */ jsxs12("span", { className: item({ active: homeHref === activeHref }), children: [
1037
- /* @__PURE__ */ jsx17("span", { className: itemIcon(), children: /* @__PURE__ */ jsx17(Icon, { name: "Home" }) }),
1038
- /* @__PURE__ */ jsx17("span", { className: itemLabel({ collapsed }), children: homeLabel })
966
+ /* @__PURE__ */ jsx15("span", { className: itemIcon(), children: /* @__PURE__ */ jsx15(Icon, { name: "Home" }) }),
967
+ /* @__PURE__ */ jsx15("span", { className: itemLabel({ collapsed }), children: homeLabel })
1039
968
  ] })
1040
969
  }
1041
970
  ),
1042
- /* @__PURE__ */ jsx17("nav", { "aria-label": "Main navigation", className: nav(), children: sections.map((sectionData, i) => /* @__PURE__ */ jsx17("div", { className: section(), children: sectionData.items.map((sidebarItem) => {
971
+ /* @__PURE__ */ jsx15("nav", { "aria-label": "Main navigation", className: nav(), children: sections.map((sectionData, i) => /* @__PURE__ */ jsx15("div", { className: section(), children: sectionData.items.map((sidebarItem) => {
1043
972
  const isActive = sidebarItem.href === activeHref;
1044
973
  return /* @__PURE__ */ jsxs12(
1045
974
  Link,
@@ -1048,20 +977,20 @@ var Sidebar = ({
1048
977
  className: item({ active: isActive }),
1049
978
  ...isActive && { "aria-current": "page" },
1050
979
  children: [
1051
- /* @__PURE__ */ jsx17("span", { className: itemIcon(), children: /* @__PURE__ */ jsx17(Icon, { name: sidebarItem.icon }) }),
1052
- /* @__PURE__ */ jsx17("span", { className: itemLabel({ collapsed }), children: sidebarItem.label })
980
+ /* @__PURE__ */ jsx15("span", { className: itemIcon(), children: /* @__PURE__ */ jsx15(Icon, { name: sidebarItem.icon }) }),
981
+ /* @__PURE__ */ jsx15("span", { className: itemLabel({ collapsed }), children: sidebarItem.label })
1053
982
  ]
1054
983
  },
1055
984
  sidebarItem.href
1056
985
  );
1057
986
  }) }, i)) }),
1058
987
  /* @__PURE__ */ jsxs12("div", { className: footer(), children: [
1059
- /* @__PURE__ */ jsx17("div", { className: avatar(), children: initials }),
988
+ /* @__PURE__ */ jsx15("div", { className: avatar(), children: initials }),
1060
989
  /* @__PURE__ */ jsxs12("div", { className: userInfo(), children: [
1061
- /* @__PURE__ */ jsx17("span", { className: userName(), children: user.name }),
1062
- /* @__PURE__ */ jsx17("span", { className: userEmail(), children: user.email })
990
+ /* @__PURE__ */ jsx15("span", { className: userName(), children: user.name }),
991
+ /* @__PURE__ */ jsx15("span", { className: userEmail(), children: user.email })
1063
992
  ] }),
1064
- /* @__PURE__ */ jsx17(
993
+ /* @__PURE__ */ jsx15(
1065
994
  Button,
1066
995
  {
1067
996
  color: "ghost",
@@ -1071,7 +1000,7 @@ var Sidebar = ({
1071
1000
  }
1072
1001
  )
1073
1002
  ] }),
1074
- /* @__PURE__ */ jsx17("div", { className: toggleButton(), children: /* @__PURE__ */ jsx17(
1003
+ /* @__PURE__ */ jsx15("div", { className: toggleButton(), children: /* @__PURE__ */ jsx15(
1075
1004
  Button,
1076
1005
  {
1077
1006
  color: "ghost",
@@ -1120,7 +1049,7 @@ var useToastStore = create()(
1120
1049
  );
1121
1050
 
1122
1051
  // core/toaster/toaster.tsx
1123
- import { jsx as jsx18 } from "react/jsx-runtime";
1052
+ import { jsx as jsx16 } from "react/jsx-runtime";
1124
1053
  var Toaster = () => {
1125
1054
  const toasts = useToastStore((s) => s.toasts);
1126
1055
  const removeToast = useToastStore((s) => s.removeToast);
@@ -1133,7 +1062,7 @@ var Toaster = () => {
1133
1062
  removeToast(t.id);
1134
1063
  });
1135
1064
  }, [toasts, removeToast]);
1136
- return /* @__PURE__ */ jsx18(
1065
+ return /* @__PURE__ */ jsx16(
1137
1066
  SonnerToaster,
1138
1067
  {
1139
1068
  position: "bottom-right",
@@ -1206,13 +1135,14 @@ var useModalStore = create3()(
1206
1135
  )
1207
1136
  );
1208
1137
 
1209
- // core/state/global-state/global-state.tsx
1138
+ // core/redux/redux-provider/redux-provider.tsx
1210
1139
  import { Provider } from "react-redux";
1140
+
1141
+ // core/redux/store/store.ts
1211
1142
  import {
1212
1143
  combineReducers,
1213
1144
  configureStore
1214
1145
  } from "@reduxjs/toolkit";
1215
- import { jsx as jsx19 } from "react/jsx-runtime";
1216
1146
  var store;
1217
1147
  var persistentReducers = {};
1218
1148
  var dynamicReducers = {};
@@ -1221,7 +1151,12 @@ var createReducer = (coreReducers) => combineReducers({
1221
1151
  ...persistentReducers,
1222
1152
  ...coreReducers
1223
1153
  });
1224
- var createStore = (reducers, middlewares, preloadedState, coreReducers) => {
1154
+ var getReduxStore = ({
1155
+ reducers,
1156
+ middlewares,
1157
+ preloadedState,
1158
+ coreReducers
1159
+ }) => {
1225
1160
  persistentReducers = reducers;
1226
1161
  if (!store) {
1227
1162
  store = configureStore({
@@ -1238,20 +1173,23 @@ var createStore = (reducers, middlewares, preloadedState, coreReducers) => {
1238
1173
  }
1239
1174
  return store;
1240
1175
  };
1241
- var GlobalState = ({
1176
+
1177
+ // core/redux/redux-provider/redux-provider.tsx
1178
+ import { jsx as jsx17 } from "react/jsx-runtime";
1179
+ var ReduxProvider = ({
1242
1180
  children,
1243
1181
  reducers = {},
1244
1182
  middlewares = [],
1245
1183
  preloadedState = {},
1246
1184
  coreReducers = {}
1247
1185
  }) => {
1248
- const reduxStore = createStore(
1186
+ const store2 = getReduxStore({
1249
1187
  reducers,
1250
1188
  middlewares,
1251
1189
  preloadedState,
1252
1190
  coreReducers
1253
- );
1254
- return /* @__PURE__ */ jsx19(Provider, { store: reduxStore, children });
1191
+ });
1192
+ return /* @__PURE__ */ jsx17(Provider, { store: store2, children });
1255
1193
  };
1256
1194
 
1257
1195
  // core/state/router/router.store.ts
@@ -1310,7 +1248,7 @@ var usePageStore = create5()(
1310
1248
  import { useEffect as useEffect2 } from "react";
1311
1249
  import { useDispatch, useStore } from "react-redux";
1312
1250
  import { useRouter } from "next/compat/router.js";
1313
- import { Fragment as Fragment4, jsx as jsx20 } from "react/jsx-runtime";
1251
+ import { Fragment as Fragment4, jsx as jsx18 } from "react/jsx-runtime";
1314
1252
  var PageWrapper = ({
1315
1253
  reducers,
1316
1254
  title: title2,
@@ -1334,11 +1272,11 @@ var PageWrapper = ({
1334
1272
  initPage(dispatch);
1335
1273
  }
1336
1274
  }, []);
1337
- return /* @__PURE__ */ jsx20(Fragment4, { children });
1275
+ return /* @__PURE__ */ jsx18(Fragment4, { children });
1338
1276
  };
1339
1277
 
1340
1278
  // core/connected-modal/connected-modal.tsx
1341
- import { jsx as jsx21 } from "react/jsx-runtime";
1279
+ import { jsx as jsx19 } from "react/jsx-runtime";
1342
1280
  var ConnectedModal = ({
1343
1281
  modalId,
1344
1282
  title: title2,
@@ -1348,7 +1286,7 @@ var ConnectedModal = ({
1348
1286
  }) => {
1349
1287
  const isOpen = useModalStore((s) => s.isOpen(modalId));
1350
1288
  const closeModal = useModalStore((s) => s.closeModal);
1351
- return /* @__PURE__ */ jsx21(
1289
+ return /* @__PURE__ */ jsx19(
1352
1290
  Modal,
1353
1291
  {
1354
1292
  open: isOpen,
@@ -1369,34 +1307,34 @@ var spinnerIcons = {
1369
1307
  };
1370
1308
 
1371
1309
  // core/spinner/spinner.styles.ts
1372
- import { tv as tv14 } from "tailwind-variants";
1373
- var spinner = tv14({
1310
+ import { tv as tv12 } from "tailwind-variants";
1311
+ var spinner = tv12({
1374
1312
  base: "inline-flex animate-spin text-white"
1375
1313
  });
1376
1314
 
1377
1315
  // core/spinner/spinner.tsx
1378
- import { jsx as jsx22 } from "react/jsx-runtime";
1379
- var Spinner = ({ variant = "circle", size = "md" }) => /* @__PURE__ */ jsx22("span", { "data-testid": "spinner", className: spinner(), children: /* @__PURE__ */ jsx22(Icon, { name: spinnerIcons[variant], size }) });
1316
+ import { jsx as jsx20 } from "react/jsx-runtime";
1317
+ var Spinner = ({ variant = "circle", size = "md" }) => /* @__PURE__ */ jsx20("span", { "data-testid": "spinner", className: spinner(), children: /* @__PURE__ */ jsx20(Icon, { name: spinnerIcons[variant], size }) });
1380
1318
 
1381
1319
  // core/loader/loader.styles.ts
1382
- import { tv as tv15 } from "tailwind-variants";
1383
- var overlay2 = tv15({
1320
+ import { tv as tv13 } from "tailwind-variants";
1321
+ var overlay2 = tv13({
1384
1322
  base: "flex fixed justify-center items-center w-full h-full bg-black/20 z-50"
1385
1323
  });
1386
1324
 
1387
1325
  // core/loader/loader.tsx
1388
- import { jsx as jsx23 } from "react/jsx-runtime";
1326
+ import { jsx as jsx21 } from "react/jsx-runtime";
1389
1327
  var Loader = ({ label: label5 = "Loading" }) => {
1390
1328
  const fetching = useAppStore((s) => s.fetching);
1391
1329
  if (!fetching) return null;
1392
- return /* @__PURE__ */ jsx23("div", { role: "status", "aria-label": label5, className: overlay2(), children: /* @__PURE__ */ jsx23(Spinner, { size: "lg" }) });
1330
+ return /* @__PURE__ */ jsx21("div", { role: "status", "aria-label": label5, className: overlay2(), children: /* @__PURE__ */ jsx21(Spinner, { size: "lg" }) });
1393
1331
  };
1394
1332
 
1395
1333
  // core/app-wrapper/app-wrapper.tsx
1396
1334
  import { useEffect as useEffect3 } from "react";
1397
1335
  import { useRouter as useRouter2 } from "next/compat/router.js";
1398
1336
  import { SessionProvider } from "next-auth/react";
1399
- import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
1337
+ import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
1400
1338
  var AppWrapper = ({
1401
1339
  children,
1402
1340
  reducers,
@@ -1410,15 +1348,15 @@ var AppWrapper = ({
1410
1348
  setRoute(router.asPath);
1411
1349
  }
1412
1350
  }, [router?.isReady, router?.asPath, setRoute]);
1413
- return /* @__PURE__ */ jsx24(SessionProvider, { children: /* @__PURE__ */ jsxs13(
1414
- GlobalState,
1351
+ return /* @__PURE__ */ jsx22(SessionProvider, { children: /* @__PURE__ */ jsxs13(
1352
+ ReduxProvider,
1415
1353
  {
1416
1354
  reducers,
1417
1355
  middlewares,
1418
1356
  coreReducers,
1419
1357
  children: [
1420
- /* @__PURE__ */ jsx24(Loader, {}),
1421
- /* @__PURE__ */ jsx24(Toaster, {}),
1358
+ /* @__PURE__ */ jsx22(Loader, {}),
1359
+ /* @__PURE__ */ jsx22(Toaster, {}),
1422
1360
  children
1423
1361
  ]
1424
1362
  }
@@ -1426,13 +1364,13 @@ var AppWrapper = ({
1426
1364
  };
1427
1365
 
1428
1366
  // core/document-wrapper/document-wrapper.tsx
1429
- import { jsx as jsx25 } from "react/jsx-runtime";
1367
+ import { jsx as jsx23 } from "react/jsx-runtime";
1430
1368
  var DocumentWrapper = ({
1431
1369
  children,
1432
1370
  lang = "pt-BR",
1433
1371
  className
1434
1372
  }) => {
1435
- return /* @__PURE__ */ jsx25("html", { lang, children: /* @__PURE__ */ jsx25("body", { className, children }) });
1373
+ return /* @__PURE__ */ jsx23("html", { lang, children: /* @__PURE__ */ jsx23("body", { className, children }) });
1436
1374
  };
1437
1375
 
1438
1376
  // core/http/http.client.ts
@@ -1517,7 +1455,6 @@ export {
1517
1455
  Form,
1518
1456
  FormInput,
1519
1457
  FormProvider,
1520
- GlobalState,
1521
1458
  HTTPClient,
1522
1459
  Heading,
1523
1460
  Icon,
@@ -1526,6 +1463,7 @@ export {
1526
1463
  Modal,
1527
1464
  PageWrapper,
1528
1465
  Radio,
1466
+ ReduxProvider,
1529
1467
  Select,
1530
1468
  Sidebar,
1531
1469
  Spinner,
@@ -1,5 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
+ import { SemanticColor } from '../index.js';
3
4
 
4
5
  interface RootLayoutProps {
5
6
  children: ReactNode;
@@ -11,9 +12,18 @@ interface NotFoundProps {
11
12
  title?: string;
12
13
  message?: string;
13
14
  backHref?: string;
15
+ backLabel?: string;
14
16
  }
15
17
 
16
- declare const NotFound: ({ title: notFoundTitle, message: notFoundMessage, backHref, }: NotFoundProps) => react.JSX.Element;
18
+ declare const NotFound: ({ title, message, backHref, backLabel, }: NotFoundProps) => react.JSX.Element;
17
19
 
18
- export { NotFound, RootLayout };
19
- export type { NotFoundProps, RootLayoutProps };
20
+ interface LinkProps {
21
+ children: ReactNode;
22
+ href: string;
23
+ color?: SemanticColor;
24
+ }
25
+
26
+ declare const Link: ({ children, href, color }: LinkProps) => react.JSX.Element;
27
+
28
+ export { Link, NotFound, RootLayout };
29
+ export type { LinkProps, NotFoundProps, RootLayoutProps };
@@ -1,50 +1,81 @@
1
1
  "use client";
2
+ import {
3
+ Heading,
4
+ Text
5
+ } from "../chunk-CXA5QIHP.js";
2
6
 
3
7
  // core/next/root-layout/root-layout.styles.ts
4
8
  import { tv } from "tailwind-variants";
5
- var body = tv({
6
- base: "min-h-screen"
9
+ var rootLayout = tv({
10
+ base: "min-h-dvh"
7
11
  });
8
12
 
9
13
  // core/next/root-layout/root-layout.tsx
10
14
  import { jsx } from "react/jsx-runtime";
11
15
  var RootLayout = ({ children }) => {
12
- return /* @__PURE__ */ jsx("main", { className: body(), children });
16
+ return /* @__PURE__ */ jsx("main", { className: rootLayout(), children });
13
17
  };
14
18
 
15
- // core/next/not-found/not-found.styles.ts
19
+ // core/next/link/link.tsx
20
+ import NextLink from "next/link.js";
21
+
22
+ // core/next/link/link.styles.ts
16
23
  import { tv as tv2 } from "tailwind-variants";
17
- var container = tv2({
18
- base: "flex flex-col items-center justify-center min-h-screen p-4"
19
- });
20
- var code = tv2({
21
- base: "text-6xl font-bold text-gray-300 mb-4"
22
- });
23
- var title = tv2({
24
- base: "text-2xl font-semibold text-gray-900 mb-2"
25
- });
26
- var message = tv2({
27
- base: "text-gray-600 mb-6 text-center max-w-md"
28
- });
29
24
  var link = tv2({
30
- base: "text-blue-600 hover:text-blue-700 hover:underline"
25
+ // outline-current draws the focus in the text color. The invisible ::after grows the touch target to 44px without changing the layout.
26
+ base: "relative rounded-sm underline underline-offset-2 hover:decoration-2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current after:absolute after:top-1/2 after:left-1/2 after:h-11 after:w-full after:min-w-11 after:-translate-x-1/2 after:-translate-y-1/2",
27
+ variants: {
28
+ color: {
29
+ primary: "text-zl-primary hover:text-zl-primary-strong",
30
+ success: "text-zl-success hover:text-zl-success-strong",
31
+ danger: "text-zl-danger hover:text-zl-danger-strong",
32
+ warning: "text-zl-warning hover:text-zl-warning-strong",
33
+ info: "text-zl-info hover:text-zl-info-strong",
34
+ muted: "text-zl-muted hover:text-zl-muted-strong",
35
+ none: ""
36
+ }
37
+ },
38
+ defaultVariants: {
39
+ color: "primary"
40
+ }
41
+ });
42
+
43
+ // core/next/link/link.tsx
44
+ import { jsx as jsx2 } from "react/jsx-runtime";
45
+ var Link = ({ children, href, color = "primary" }) => {
46
+ return /* @__PURE__ */ jsx2(NextLink, { href, className: link({ color }), children });
47
+ };
48
+
49
+ // core/next/not-found/not-found.styles.ts
50
+ import { tv as tv3 } from "tailwind-variants";
51
+ var notFound = tv3({
52
+ slots: {
53
+ base: "flex flex-col items-center justify-center gap-6 min-h-dvh p-4 text-center",
54
+ code: "text-6xl font-bold text-zl-muted",
55
+ content: "flex flex-col gap-2 max-w-md"
56
+ }
31
57
  });
32
58
 
33
59
  // core/next/not-found/not-found.tsx
34
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
60
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
35
61
  var NotFound = ({
36
- title: notFoundTitle = "Page not found",
37
- message: notFoundMessage = "The page you are looking for does not exist.",
38
- backHref = "/"
62
+ title = "Page not found",
63
+ message = "The page you are looking for does not exist.",
64
+ backHref = "/",
65
+ backLabel = "Go back home"
39
66
  }) => {
40
- return /* @__PURE__ */ jsxs("div", { className: container(), children: [
41
- /* @__PURE__ */ jsx2("span", { className: code(), children: "404" }),
42
- /* @__PURE__ */ jsx2("h1", { className: title(), children: notFoundTitle }),
43
- /* @__PURE__ */ jsx2("p", { className: message(), children: notFoundMessage }),
44
- /* @__PURE__ */ jsx2("a", { href: backHref, className: link(), children: "Go back home" })
67
+ const { base, code, content } = notFound();
68
+ return /* @__PURE__ */ jsxs("div", { className: base(), children: [
69
+ /* @__PURE__ */ jsx3("span", { className: code(), children: "404" }),
70
+ /* @__PURE__ */ jsxs("div", { className: content(), children: [
71
+ /* @__PURE__ */ jsx3(Heading, { children: title }),
72
+ /* @__PURE__ */ jsx3(Text, { color: "muted", children: message })
73
+ ] }),
74
+ /* @__PURE__ */ jsx3(Link, { href: backHref, children: backLabel })
45
75
  ] });
46
76
  };
47
77
  export {
78
+ Link,
48
79
  NotFound,
49
80
  RootLayout
50
81
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexandregme/zljs",
3
- "version": "1.15.0",
3
+ "version": "1.17.0",
4
4
  "description": "Opinionated, accessible React component library for enterprise apps (Next.js, Tailwind CSS v4).",
5
5
  "keywords": [
6
6
  "react",