@alexandregme/zljs 1.15.0 → 1.16.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,23 @@ A change that needs action in an app has a **Migration** note. When updating, re
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.16.0] - 2026-11-02
12
+
13
+ ### Added
14
+
15
+ - `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
16
+ - `NotFound` takes `backLabel`. "Go back home" was fixed, so an app in another language couldn't translate it
17
+
18
+ ### Changed
19
+
20
+ - `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
21
+ - `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
22
+ - `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
23
+
24
+ ### Fixed
25
+
26
+ - 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
27
+
11
28
  ## [1.15.0] - 2026-11-02
12
29
 
13
30
  ### Added
@@ -190,7 +207,8 @@ Replace the shade with the class of the `color` being tested, for example `/(^|\
190
207
 
191
208
  The message of `Error` is `text-zl-danger`. `none` and `ghost` didn't change.
192
209
 
193
- [Unreleased]: https://github.com/alexandregme/zljs/compare/v1.15.0...HEAD
210
+ [Unreleased]: https://github.com/alexandregme/zljs/compare/v1.16.0...HEAD
211
+ [1.16.0]: https://github.com/alexandregme/zljs/compare/v1.15.0...v1.16.0
194
212
  [1.15.0]: https://github.com/alexandregme/zljs/compare/v1.14.0...v1.15.0
195
213
  [1.14.0]: https://github.com/alexandregme/zljs/compare/v1.13.0...v1.14.0
196
214
  [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
7
  import { Store, Reducer, Middleware, 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
  */
@@ -506,5 +498,5 @@ declare class HTTPClient {
506
498
  patch<T = unknown>(url: string, config?: HttpRequestConfig): Promise<T | undefined>;
507
499
  }
508
500
 
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 };
501
+ export { AppWrapper, Button, Checkbox, ConnectedModal, DataColor, DataGrid, DocumentWrapper, Error, Form, GlobalState, HTTPClient, Heading, Icon, Input, Loader, Modal, PageWrapper, Radio, Select, SemanticColor, Sidebar, Spinner, StatsCard, Tag, Text, TextArea, Toaster, WhatsAppButton, splitURLasPath, useAppStore, useModalStore, usePageStore, useRouterStore, useToastStore };
502
+ export type { AppState, AppWrapperProps, ButtonColor, ButtonProps, ButtonVariant, CheckboxProps, CheckboxVariant, ConnectedModalProps, DataGridColumn, DataGridProps, DocumentWrapperProps, ErrorProps, ExtendedStore, FormProps, GlobalStateProps, HeadingProps, HttpClientConfig, HttpRequestConfig, IconName, IconProps, InitPageFunction, InputProps, LoaderProps, ModalEntry, ModalProps, ModalState, PageState, PageWrapperProps, RadioProps, 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",
@@ -1212,7 +1141,7 @@ import {
1212
1141
  combineReducers,
1213
1142
  configureStore
1214
1143
  } from "@reduxjs/toolkit";
1215
- import { jsx as jsx19 } from "react/jsx-runtime";
1144
+ import { jsx as jsx17 } from "react/jsx-runtime";
1216
1145
  var store;
1217
1146
  var persistentReducers = {};
1218
1147
  var dynamicReducers = {};
@@ -1251,7 +1180,7 @@ var GlobalState = ({
1251
1180
  preloadedState,
1252
1181
  coreReducers
1253
1182
  );
1254
- return /* @__PURE__ */ jsx19(Provider, { store: reduxStore, children });
1183
+ return /* @__PURE__ */ jsx17(Provider, { store: reduxStore, children });
1255
1184
  };
1256
1185
 
1257
1186
  // core/state/router/router.store.ts
@@ -1310,7 +1239,7 @@ var usePageStore = create5()(
1310
1239
  import { useEffect as useEffect2 } from "react";
1311
1240
  import { useDispatch, useStore } from "react-redux";
1312
1241
  import { useRouter } from "next/compat/router.js";
1313
- import { Fragment as Fragment4, jsx as jsx20 } from "react/jsx-runtime";
1242
+ import { Fragment as Fragment4, jsx as jsx18 } from "react/jsx-runtime";
1314
1243
  var PageWrapper = ({
1315
1244
  reducers,
1316
1245
  title: title2,
@@ -1334,11 +1263,11 @@ var PageWrapper = ({
1334
1263
  initPage(dispatch);
1335
1264
  }
1336
1265
  }, []);
1337
- return /* @__PURE__ */ jsx20(Fragment4, { children });
1266
+ return /* @__PURE__ */ jsx18(Fragment4, { children });
1338
1267
  };
1339
1268
 
1340
1269
  // core/connected-modal/connected-modal.tsx
1341
- import { jsx as jsx21 } from "react/jsx-runtime";
1270
+ import { jsx as jsx19 } from "react/jsx-runtime";
1342
1271
  var ConnectedModal = ({
1343
1272
  modalId,
1344
1273
  title: title2,
@@ -1348,7 +1277,7 @@ var ConnectedModal = ({
1348
1277
  }) => {
1349
1278
  const isOpen = useModalStore((s) => s.isOpen(modalId));
1350
1279
  const closeModal = useModalStore((s) => s.closeModal);
1351
- return /* @__PURE__ */ jsx21(
1280
+ return /* @__PURE__ */ jsx19(
1352
1281
  Modal,
1353
1282
  {
1354
1283
  open: isOpen,
@@ -1369,34 +1298,34 @@ var spinnerIcons = {
1369
1298
  };
1370
1299
 
1371
1300
  // core/spinner/spinner.styles.ts
1372
- import { tv as tv14 } from "tailwind-variants";
1373
- var spinner = tv14({
1301
+ import { tv as tv12 } from "tailwind-variants";
1302
+ var spinner = tv12({
1374
1303
  base: "inline-flex animate-spin text-white"
1375
1304
  });
1376
1305
 
1377
1306
  // 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 }) });
1307
+ import { jsx as jsx20 } from "react/jsx-runtime";
1308
+ var Spinner = ({ variant = "circle", size = "md" }) => /* @__PURE__ */ jsx20("span", { "data-testid": "spinner", className: spinner(), children: /* @__PURE__ */ jsx20(Icon, { name: spinnerIcons[variant], size }) });
1380
1309
 
1381
1310
  // core/loader/loader.styles.ts
1382
- import { tv as tv15 } from "tailwind-variants";
1383
- var overlay2 = tv15({
1311
+ import { tv as tv13 } from "tailwind-variants";
1312
+ var overlay2 = tv13({
1384
1313
  base: "flex fixed justify-center items-center w-full h-full bg-black/20 z-50"
1385
1314
  });
1386
1315
 
1387
1316
  // core/loader/loader.tsx
1388
- import { jsx as jsx23 } from "react/jsx-runtime";
1317
+ import { jsx as jsx21 } from "react/jsx-runtime";
1389
1318
  var Loader = ({ label: label5 = "Loading" }) => {
1390
1319
  const fetching = useAppStore((s) => s.fetching);
1391
1320
  if (!fetching) return null;
1392
- return /* @__PURE__ */ jsx23("div", { role: "status", "aria-label": label5, className: overlay2(), children: /* @__PURE__ */ jsx23(Spinner, { size: "lg" }) });
1321
+ return /* @__PURE__ */ jsx21("div", { role: "status", "aria-label": label5, className: overlay2(), children: /* @__PURE__ */ jsx21(Spinner, { size: "lg" }) });
1393
1322
  };
1394
1323
 
1395
1324
  // core/app-wrapper/app-wrapper.tsx
1396
1325
  import { useEffect as useEffect3 } from "react";
1397
1326
  import { useRouter as useRouter2 } from "next/compat/router.js";
1398
1327
  import { SessionProvider } from "next-auth/react";
1399
- import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
1328
+ import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
1400
1329
  var AppWrapper = ({
1401
1330
  children,
1402
1331
  reducers,
@@ -1410,15 +1339,15 @@ var AppWrapper = ({
1410
1339
  setRoute(router.asPath);
1411
1340
  }
1412
1341
  }, [router?.isReady, router?.asPath, setRoute]);
1413
- return /* @__PURE__ */ jsx24(SessionProvider, { children: /* @__PURE__ */ jsxs13(
1342
+ return /* @__PURE__ */ jsx22(SessionProvider, { children: /* @__PURE__ */ jsxs13(
1414
1343
  GlobalState,
1415
1344
  {
1416
1345
  reducers,
1417
1346
  middlewares,
1418
1347
  coreReducers,
1419
1348
  children: [
1420
- /* @__PURE__ */ jsx24(Loader, {}),
1421
- /* @__PURE__ */ jsx24(Toaster, {}),
1349
+ /* @__PURE__ */ jsx22(Loader, {}),
1350
+ /* @__PURE__ */ jsx22(Toaster, {}),
1422
1351
  children
1423
1352
  ]
1424
1353
  }
@@ -1426,13 +1355,13 @@ var AppWrapper = ({
1426
1355
  };
1427
1356
 
1428
1357
  // core/document-wrapper/document-wrapper.tsx
1429
- import { jsx as jsx25 } from "react/jsx-runtime";
1358
+ import { jsx as jsx23 } from "react/jsx-runtime";
1430
1359
  var DocumentWrapper = ({
1431
1360
  children,
1432
1361
  lang = "pt-BR",
1433
1362
  className
1434
1363
  }) => {
1435
- return /* @__PURE__ */ jsx25("html", { lang, children: /* @__PURE__ */ jsx25("body", { className, children }) });
1364
+ return /* @__PURE__ */ jsx23("html", { lang, children: /* @__PURE__ */ jsx23("body", { className, children }) });
1436
1365
  };
1437
1366
 
1438
1367
  // core/http/http.client.ts
@@ -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.16.0",
4
4
  "description": "Opinionated, accessible React component library for enterprise apps (Next.js, Tailwind CSS v4).",
5
5
  "keywords": [
6
6
  "react",