@alexandregme/zljs 1.13.1 → 1.15.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,34 @@ A change that needs action in an app has a **Migration** note. When updating, re
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.15.0] - 2026-11-02
12
+
13
+ ### Added
14
+
15
+ - `Icon` takes `color`, with the same `SemanticColor` values as `Text` and `Heading`. With no `color`, or with `none`, it still inherits the color around it
16
+
17
+ ## [1.14.0] - 2026-11-02
18
+
19
+ ### Changed
20
+
21
+ - The box of a `Checkbox` with `variant="card"` is centered on the height of its content, instead of sitting at the top. With several lines, it is no longer beside the first one
22
+
23
+ ### Fixed
24
+
25
+ - A checked `Checkbox` uses the theme's `primary` color. It had `text-blue-600`, which does nothing on a native checkbox, so it kept the browser's own color, and an app's theme only reached the border of a `card`
26
+
27
+ #### Migration
28
+
29
+ Every `Checkbox` with `variant="card"` looks different, so check those screens. Code only needs a change if it forces the alignment from outside, or if a test asserts `items-start` on the card. To find them, run the commands below from the app's root. The first also finds other components named `Checkbox` and any `variant`, and the last also finds `items-start` set by the app, and those stay as they are:
30
+
31
+ ```sh
32
+ grep -rnE -A6 "<Checkbox([[:space:]/>]|$)" . --include='*.tsx' --exclude-dir=node_modules --exclude-dir=.next | grep -E "variant="
33
+ grep -rnE "\[&_label\]:items-" . --include='*.ts' --include='*.tsx' --exclude-dir=node_modules --exclude-dir=.next
34
+ grep -rnE "items-start" . --include='*.test.*' --exclude-dir=node_modules --exclude-dir=.next
35
+ ```
36
+
37
+ Remove a wrapper that only sets `[&_label]:items-center`, and the test that asserts it. In tests, replace `items-start` with `items-center`.
38
+
11
39
  ## [1.13.0] - 2026-11-02
12
40
 
13
41
  ### Added
@@ -162,7 +190,9 @@ Replace the shade with the class of the `color` being tested, for example `/(^|\
162
190
 
163
191
  The message of `Error` is `text-zl-danger`. `none` and `ghost` didn't change.
164
192
 
165
- [Unreleased]: https://github.com/alexandregme/zljs/compare/v1.13.0...HEAD
193
+ [Unreleased]: https://github.com/alexandregme/zljs/compare/v1.15.0...HEAD
194
+ [1.15.0]: https://github.com/alexandregme/zljs/compare/v1.14.0...v1.15.0
195
+ [1.14.0]: https://github.com/alexandregme/zljs/compare/v1.13.0...v1.14.0
166
196
  [1.13.0]: https://github.com/alexandregme/zljs/compare/v1.12.0...v1.13.0
167
197
  [1.12.0]: https://github.com/alexandregme/zljs/compare/v1.11.0...v1.12.0
168
198
  [1.11.0]: https://github.com/alexandregme/zljs/compare/v1.10.0...v1.11.0
package/dist/index.d.ts CHANGED
@@ -26,6 +26,7 @@ type IconName = (typeof iconNames)[number];
26
26
  interface IconProps {
27
27
  name: IconName;
28
28
  size?: Size;
29
+ color?: SemanticColor;
29
30
  "aria-label"?: string;
30
31
  }
31
32
 
@@ -195,7 +196,7 @@ type TextAreaProps = TextAreaName & {
195
196
 
196
197
  declare const TextArea: ({ label: labelText, "aria-label": ariaLabel, name, placeholder, autoComplete, value, rows, error, disabled, required, onChange, onBlur, onKeyDown, ref, }: TextAreaProps) => react.JSX.Element;
197
198
 
198
- declare const Icon: ({ name, size, "aria-label": ariaLabel, }: IconProps) => react.JSX.Element;
199
+ declare const Icon: ({ name, size, color, "aria-label": ariaLabel, }: IconProps) => react.JSX.Element;
199
200
 
200
201
  interface StatsCardProps {
201
202
  label: string;
package/dist/index.js CHANGED
@@ -23,11 +23,33 @@ var iconSizes = {
23
23
  lg: 24
24
24
  };
25
25
 
26
+ // core/icon/icon.styles.ts
27
+ 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
+ var icon = tv({
42
+ variants: {
43
+ color: semanticTextColors
44
+ }
45
+ });
46
+
26
47
  // core/icon/icon.tsx
27
48
  import { Fragment, jsx } from "react/jsx-runtime";
28
49
  var Icon = ({
29
50
  name,
30
51
  size = "md",
52
+ color,
31
53
  "aria-label": ariaLabel
32
54
  }) => {
33
55
  const isBrand = name.startsWith("Si");
@@ -37,6 +59,7 @@ var Icon = ({
37
59
  "span",
38
60
  {
39
61
  "data-testid": name,
62
+ className: icon({ color }),
40
63
  role: ariaLabel ? "img" : void 0,
41
64
  "aria-label": ariaLabel,
42
65
  children: /* @__PURE__ */ jsx(IconComponent, { size: iconSizes[size], "aria-hidden": "true" })
@@ -45,8 +68,8 @@ var Icon = ({
45
68
  };
46
69
 
47
70
  // core/button/button.styles.ts
48
- import { tv } from "tailwind-variants";
49
- var button = tv({
71
+ import { tv as tv2 } from "tailwind-variants";
72
+ var button = tv2({
50
73
  // outline-current covers the colors with no outline class (ghost, none): without it, browsers keep their default focus color.
51
74
  base: "cursor-pointer font-medium focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center justify-center",
52
75
  variants: {
@@ -157,19 +180,19 @@ var Button = ({
157
180
  color = "primary",
158
181
  size = "md",
159
182
  fullWidth = false,
160
- icon,
183
+ icon: icon2,
161
184
  iconPosition = "left",
162
185
  disabled = false,
163
186
  "aria-label": ariaLabel,
164
187
  onClick
165
188
  }) => {
166
- const isIconOnly = icon && !children;
189
+ const isIconOnly = icon2 && !children;
167
190
  const variant = variantProp ?? (isIconOnly ? "icon" : "default");
168
191
  const renderContent = () => {
169
- if (!icon) {
192
+ if (!icon2) {
170
193
  return children;
171
194
  }
172
- const iconElement = /* @__PURE__ */ jsx2(Icon, { name: icon, size });
195
+ const iconElement = /* @__PURE__ */ jsx2(Icon, { name: icon2, size });
173
196
  if (isIconOnly) {
174
197
  return iconElement;
175
198
  }
@@ -215,24 +238,24 @@ import { useState } from "react";
215
238
  import { useId } from "react";
216
239
 
217
240
  // core/forms/checkbox/checkbox.styles.ts
218
- import { tv as tv2 } from "tailwind-variants";
219
- var wrapper = tv2({
241
+ import { tv as tv3 } from "tailwind-variants";
242
+ var wrapper = tv3({
220
243
  base: "flex flex-col gap-1"
221
244
  });
222
- var innerWrapper = tv2({
245
+ var innerWrapper = tv3({
223
246
  base: "flex cursor-pointer has-disabled:cursor-not-allowed",
224
247
  variants: {
225
248
  variant: {
226
249
  default: "w-fit items-center gap-2",
227
- card: "items-start gap-3 rounded-lg border border-gray-500 p-3 has-checked:border-zl-primary has-checked:ring-1 has-checked:ring-zl-primary has-disabled:bg-gray-100"
250
+ card: "items-center gap-3 rounded-lg border border-gray-500 p-3 has-checked:border-zl-primary has-checked:ring-1 has-checked:ring-zl-primary has-disabled:bg-gray-100"
228
251
  }
229
252
  },
230
253
  defaultVariants: {
231
254
  variant: "default"
232
255
  }
233
256
  });
234
- var checkbox = tv2({
235
- base: "shrink-0 text-blue-600 border-gray-300 rounded focus:ring-2 focus:ring-blue-500 disabled:cursor-not-allowed",
257
+ var checkbox = tv3({
258
+ base: "shrink-0 accent-zl-primary border-gray-300 rounded focus:ring-2 focus:ring-blue-500 disabled:cursor-not-allowed",
236
259
  variants: {
237
260
  size: {
238
261
  sm: "w-3.5 h-3.5",
@@ -244,7 +267,7 @@ var checkbox = tv2({
244
267
  size: "md"
245
268
  }
246
269
  });
247
- var label = tv2({
270
+ var label = tv3({
248
271
  base: "min-w-0 flex-1 text-sm text-gray-700 select-none"
249
272
  });
250
273
 
@@ -285,8 +308,8 @@ var Checkbox = ({
285
308
  };
286
309
 
287
310
  // core/forms/form/form.styles.ts
288
- import { tv as tv3 } from "tailwind-variants";
289
- var fieldset = tv3({
311
+ import { tv as tv4 } from "tailwind-variants";
312
+ var fieldset = tv4({
290
313
  base: "border-none p-0"
291
314
  });
292
315
 
@@ -304,14 +327,14 @@ var Form = ({ children, onSubmit, disabled }) => {
304
327
  import { useId as useId2 } from "react";
305
328
 
306
329
  // core/forms/radio/radio.styles.ts
307
- import { tv as tv4 } from "tailwind-variants";
308
- var wrapper2 = tv4({
330
+ import { tv as tv5 } from "tailwind-variants";
331
+ var wrapper2 = tv5({
309
332
  base: "flex w-fit items-center gap-2 cursor-pointer has-disabled:cursor-not-allowed"
310
333
  });
311
- var radio = tv4({
334
+ var radio = tv5({
312
335
  base: "w-4 h-4 shrink-0 accent-zl-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zl-primary disabled:cursor-not-allowed"
313
336
  });
314
- var label2 = tv4({
337
+ var label2 = tv5({
315
338
  base: "text-sm text-gray-700 select-none"
316
339
  });
317
340
 
@@ -358,14 +381,14 @@ var Radio = ({
358
381
  import { useId as useId3 } from "react";
359
382
 
360
383
  // core/forms/select/select.styles.ts
361
- import { tv as tv5 } from "tailwind-variants";
362
- var wrapper3 = tv5({
384
+ import { tv as tv6 } from "tailwind-variants";
385
+ var wrapper3 = tv6({
363
386
  base: "flex flex-col gap-1"
364
387
  });
365
- var label3 = tv5({
388
+ var label3 = tv6({
366
389
  base: "text-sm font-medium text-gray-700"
367
390
  });
368
- var select = tv5({
391
+ var select = tv6({
369
392
  base: "px-3 py-2 border border-gray-500 rounded-md text-sm bg-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zl-primary disabled:bg-gray-100 disabled:cursor-not-allowed"
370
393
  });
371
394
 
@@ -423,14 +446,14 @@ var Select = ({
423
446
  import { useId as useId4 } from "react";
424
447
 
425
448
  // core/forms/text-area/text-area.styles.ts
426
- import { tv as tv6 } from "tailwind-variants";
427
- var wrapper4 = tv6({
449
+ import { tv as tv7 } from "tailwind-variants";
450
+ var wrapper4 = tv7({
428
451
  base: "flex flex-col gap-1"
429
452
  });
430
- var label4 = tv6({
453
+ var label4 = tv7({
431
454
  base: "text-sm font-medium text-gray-700"
432
455
  });
433
- var textarea = tv6({
456
+ var textarea = tv7({
434
457
  base: "px-3 py-2 border border-gray-500 rounded-md text-sm placeholder:text-gray-500 resize-y focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zl-primary disabled:bg-gray-100 disabled:cursor-not-allowed"
435
458
  });
436
459
 
@@ -521,8 +544,8 @@ var DataGridToolbar = ({ gridApi }) => {
521
544
  };
522
545
 
523
546
  // core/tag/tag.styles.ts
524
- import { tv as tv7 } from "tailwind-variants";
525
- var tag = tv7({
547
+ import { tv as tv8 } from "tailwind-variants";
548
+ var tag = tv8({
526
549
  base: "inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium",
527
550
  variants: {
528
551
  color: {
@@ -722,21 +745,8 @@ var DataGrid = ({
722
745
  };
723
746
 
724
747
  // core/text/text.styles.ts
725
- import { tv as tv8 } from "tailwind-variants";
726
-
727
- // core/types/colors/colors.const.ts
728
- var semanticTextColors = {
729
- primary: "text-zl-primary",
730
- success: "text-zl-success",
731
- danger: "text-zl-danger",
732
- warning: "text-zl-warning",
733
- info: "text-zl-info",
734
- muted: "text-zl-muted",
735
- none: ""
736
- };
737
-
738
- // core/text/text.styles.ts
739
- var text = tv8({
748
+ import { tv as tv9 } from "tailwind-variants";
749
+ var text = tv9({
740
750
  variants: {
741
751
  variant: {
742
752
  body: "text-base",
@@ -762,8 +772,8 @@ var Text = ({
762
772
  };
763
773
 
764
774
  // core/stats-card/stats-card.styles.ts
765
- import { tv as tv9 } from "tailwind-variants";
766
- var statsCard = tv9({
775
+ import { tv as tv10 } from "tailwind-variants";
776
+ var statsCard = tv10({
767
777
  base: "p-4 rounded-lg",
768
778
  variants: {
769
779
  color: {
@@ -790,11 +800,11 @@ var StatsCard = ({ label: label5, value, color }) => {
790
800
  import * as Dialog from "@radix-ui/react-dialog";
791
801
 
792
802
  // core/modal/modal.styles.ts
793
- import { tv as tv10 } from "tailwind-variants";
794
- var overlay = tv10({
803
+ import { tv as tv11 } from "tailwind-variants";
804
+ var overlay = tv11({
795
805
  base: "fixed inset-0 bg-black/50"
796
806
  });
797
- var content = tv10({
807
+ var content = tv11({
798
808
  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",
799
809
  variants: {
800
810
  size: {
@@ -809,16 +819,16 @@ var content = tv10({
809
819
  size: "md"
810
820
  }
811
821
  });
812
- var header = tv10({
822
+ var header = tv11({
813
823
  base: "flex items-start justify-between"
814
824
  });
815
- var title = tv10({
825
+ var title = tv11({
816
826
  base: "text-lg font-semibold text-gray-900 m-0"
817
827
  });
818
- var description = tv10({
828
+ var description = tv11({
819
829
  base: "text-sm text-gray-600 mt-2"
820
830
  });
821
- var body = tv10({
831
+ var body = tv11({
822
832
  base: "mt-4"
823
833
  });
824
834
 
@@ -897,8 +907,8 @@ var headingTags = {
897
907
  };
898
908
 
899
909
  // core/heading/heading.styles.ts
900
- import { tv as tv11 } from "tailwind-variants";
901
- var heading = tv11({
910
+ import { tv as tv12 } from "tailwind-variants";
911
+ var heading = tv12({
902
912
  variants: {
903
913
  level: {
904
914
  1: "text-3xl font-bold",
@@ -927,8 +937,8 @@ import { useState as useState3 } from "react";
927
937
  import Link from "next/link.js";
928
938
 
929
939
  // core/sidebar/sidebar.styles.ts
930
- import { tv as tv12 } from "tailwind-variants";
931
- var sidebar = tv12({
940
+ import { tv as tv13 } from "tailwind-variants";
941
+ var sidebar = tv13({
932
942
  base: "h-screen bg-neutral-800 text-neutral-300 flex flex-col overflow-hidden transition-all duration-200",
933
943
  variants: {
934
944
  collapsed: {
@@ -940,16 +950,16 @@ var sidebar = tv12({
940
950
  collapsed: false
941
951
  }
942
952
  });
943
- var nav = tv12({
953
+ var nav = tv13({
944
954
  base: "flex-1 min-h-0 overflow-y-auto overflow-x-hidden"
945
955
  });
946
- var header2 = tv12({
956
+ var header2 = tv13({
947
957
  base: "shrink-0 border-b border-neutral-600/50 grid p-2"
948
958
  });
949
- var section = tv12({
959
+ var section = tv13({
950
960
  base: "border-b border-neutral-600/50 last:border-b-0 grid gap-1 p-2"
951
961
  });
952
- var item = tv12({
962
+ var item = tv13({
953
963
  base: "flex w-full items-center rounded-md text-sm whitespace-nowrap transition-colors cursor-pointer p-1",
954
964
  variants: {
955
965
  active: {
@@ -961,10 +971,10 @@ var item = tv12({
961
971
  active: false
962
972
  }
963
973
  });
964
- var itemIcon = tv12({
974
+ var itemIcon = tv13({
965
975
  base: "p-2"
966
976
  });
967
- var itemLabel = tv12({
977
+ var itemLabel = tv13({
968
978
  base: "truncate transition-all duration-200",
969
979
  variants: {
970
980
  collapsed: {
@@ -976,22 +986,22 @@ var itemLabel = tv12({
976
986
  collapsed: false
977
987
  }
978
988
  });
979
- var footer = tv12({
989
+ var footer = tv13({
980
990
  base: "shrink-0 border-t border-neutral-600/50 p-3 flex items-center gap-3 whitespace-nowrap"
981
991
  });
982
- var avatar = tv12({
992
+ var avatar = tv13({
983
993
  base: "shrink-0 w-8 h-8 rounded-full bg-neutral-600 text-white text-xs font-medium flex items-center justify-center"
984
994
  });
985
- var userInfo = tv12({
995
+ var userInfo = tv13({
986
996
  base: "flex flex-col min-w-0"
987
997
  });
988
- var userName = tv12({
998
+ var userName = tv13({
989
999
  base: "text-sm text-white truncate"
990
1000
  });
991
- var userEmail = tv12({
1001
+ var userEmail = tv13({
992
1002
  base: "text-xs text-neutral-400"
993
1003
  });
994
- var toggleButton = tv12({
1004
+ var toggleButton = tv13({
995
1005
  base: "shrink-0 border-t border-neutral-600/50 grid p-2 [&>button]:justify-start [&>button]:overflow-hidden [&>button]:whitespace-nowrap"
996
1006
  });
997
1007
 
@@ -1359,8 +1369,8 @@ var spinnerIcons = {
1359
1369
  };
1360
1370
 
1361
1371
  // core/spinner/spinner.styles.ts
1362
- import { tv as tv13 } from "tailwind-variants";
1363
- var spinner = tv13({
1372
+ import { tv as tv14 } from "tailwind-variants";
1373
+ var spinner = tv14({
1364
1374
  base: "inline-flex animate-spin text-white"
1365
1375
  });
1366
1376
 
@@ -1369,8 +1379,8 @@ import { jsx as jsx22 } from "react/jsx-runtime";
1369
1379
  var Spinner = ({ variant = "circle", size = "md" }) => /* @__PURE__ */ jsx22("span", { "data-testid": "spinner", className: spinner(), children: /* @__PURE__ */ jsx22(Icon, { name: spinnerIcons[variant], size }) });
1370
1380
 
1371
1381
  // core/loader/loader.styles.ts
1372
- import { tv as tv14 } from "tailwind-variants";
1373
- var overlay2 = tv14({
1382
+ import { tv as tv15 } from "tailwind-variants";
1383
+ var overlay2 = tv15({
1374
1384
  base: "flex fixed justify-center items-center w-full h-full bg-black/20 z-50"
1375
1385
  });
1376
1386
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexandregme/zljs",
3
- "version": "1.13.1",
3
+ "version": "1.15.0",
4
4
  "description": "Opinionated, accessible React component library for enterprise apps (Next.js, Tailwind CSS v4).",
5
5
  "keywords": [
6
6
  "react",