@alexandregme/zljs 1.18.1 → 1.19.1
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 +42 -1
- package/dist/{chunk-KPSFYQYV.js → chunk-O6UAZGBC.js} +18 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +41 -47
- package/dist/next/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,45 @@ A change that needs action in an app has a **Migration** note. When updating, re
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [1.19.1] - 2026-11-03
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Collapsed `Sidebar` shows only the logout button in its footer. The avatar, name and email come back when it expands, and the footer and the collapse button keep their height in both states, at 64px and 56px
|
|
16
|
+
- The collapse button of `Sidebar` is named by `collapseLabel` while expanded, no longer `Collapse sidebar`, and shows only its icon when collapsed
|
|
17
|
+
- `Sidebar` links have fewer elements and look the same: the `Icon` is a direct child of the link, and the home link has no empty `span` when there is no `homeLabel`
|
|
18
|
+
|
|
19
|
+
#### Migration
|
|
20
|
+
|
|
21
|
+
Search the app's tests for `Collapse sidebar` and replace it with the value the app passes in `collapseLabel`. `Expand sidebar` stays.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Collapsed `Sidebar` can log out with a mouse. The button sat outside the visible area, and focusing it with the keyboard scrolled the sidebar sideways, out of view
|
|
26
|
+
- `Sidebar` links draw their own focus outline in the text color. They relied on the browser's default, which was 2.53:1 in Chromium
|
|
27
|
+
- The active home link of `Sidebar` has `aria-current="page"`, its link is styled like the others, and the avatar initials are hidden from screen readers
|
|
28
|
+
- A long email in `Sidebar` is cut with an ellipsis. It ran under the logout button
|
|
29
|
+
- The icon of the `Sidebar` collapse button lines up with the link icons, so it is centered when collapsed and doesn't move on toggle. It sat 4px to the right
|
|
30
|
+
|
|
31
|
+
## [1.19.0] - 2026-11-02
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- `label` on `Spinner`: the name screen readers announce, `Loading` by default
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- `Spinner` is a status with a name (`role="status"`) and has no color of its own. It was always white, and now inherits the color from around it
|
|
40
|
+
- `Loader` draws its spinner in the `primary` color, which holds 3:1 over the overlay on a white page. It was white, at 1.6:1. The `status` role moved from the overlay to the spinner, which takes the `label`
|
|
41
|
+
|
|
42
|
+
#### Migration
|
|
43
|
+
|
|
44
|
+
Search the app for `<Spinner`. On a dark surface, set a light text color around it, such as `text-white`. Remove a `role="status"` the app put around a `Spinner`, so there aren't two. `Loader` needs no change.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- `Loader` covers the whole page. It had no position of its own, so it started where it was rendered, below anything before it
|
|
49
|
+
|
|
11
50
|
## [1.18.1] - 2026-11-02
|
|
12
51
|
|
|
13
52
|
### Removed
|
|
@@ -263,7 +302,9 @@ Replace the shade with the class of the `color` being tested, for example `/(^|\
|
|
|
263
302
|
|
|
264
303
|
The message of `Error` is `text-zl-danger`. `none` and `ghost` didn't change.
|
|
265
304
|
|
|
266
|
-
[Unreleased]: https://github.com/alexandregme/zljs/compare/v1.
|
|
305
|
+
[Unreleased]: https://github.com/alexandregme/zljs/compare/v1.19.1...HEAD
|
|
306
|
+
[1.19.1]: https://github.com/alexandregme/zljs/compare/v1.19.0...v1.19.1
|
|
307
|
+
[1.19.0]: https://github.com/alexandregme/zljs/compare/v1.18.1...v1.19.0
|
|
267
308
|
[1.18.1]: https://github.com/alexandregme/zljs/compare/v1.18.0...v1.18.1
|
|
268
309
|
[1.18.0]: https://github.com/alexandregme/zljs/compare/v1.17.0...v1.18.0
|
|
269
310
|
[1.17.0]: https://github.com/alexandregme/zljs/compare/v1.16.0...v1.17.0
|
|
@@ -352,17 +352,30 @@ var spinnerIcons = {
|
|
|
352
352
|
// core/spinner/spinner.styles.ts
|
|
353
353
|
import { tv as tv4 } from "tailwind-variants";
|
|
354
354
|
var spinner = tv4({
|
|
355
|
-
base: "inline-flex animate-spin
|
|
355
|
+
base: "inline-flex animate-spin"
|
|
356
356
|
});
|
|
357
357
|
|
|
358
358
|
// core/spinner/spinner.tsx
|
|
359
359
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
360
|
-
var Spinner = ({
|
|
360
|
+
var Spinner = ({
|
|
361
|
+
variant = "circle",
|
|
362
|
+
size = "md",
|
|
363
|
+
label = "Loading"
|
|
364
|
+
}) => /* @__PURE__ */ jsx6(
|
|
365
|
+
"span",
|
|
366
|
+
{
|
|
367
|
+
"data-testid": "spinner",
|
|
368
|
+
role: "status",
|
|
369
|
+
"aria-label": label,
|
|
370
|
+
className: spinner(),
|
|
371
|
+
children: /* @__PURE__ */ jsx6(Icon, { name: spinnerIcons[variant], size })
|
|
372
|
+
}
|
|
373
|
+
);
|
|
361
374
|
|
|
362
375
|
// core/loader/loader.styles.ts
|
|
363
376
|
import { tv as tv5 } from "tailwind-variants";
|
|
364
|
-
var
|
|
365
|
-
base: "flex fixed justify-center items-center
|
|
377
|
+
var loader = tv5({
|
|
378
|
+
base: "flex fixed inset-0 justify-center items-center bg-black/20 text-zl-primary z-50"
|
|
366
379
|
});
|
|
367
380
|
|
|
368
381
|
// core/loader/loader.tsx
|
|
@@ -370,7 +383,7 @@ import { jsx as jsx7 } from "react/jsx-runtime";
|
|
|
370
383
|
var Loader = ({ label = "Loading" }) => {
|
|
371
384
|
const fetching = useAppStore((s) => s.fetching);
|
|
372
385
|
if (!fetching) return null;
|
|
373
|
-
return /* @__PURE__ */ jsx7("div", {
|
|
386
|
+
return /* @__PURE__ */ jsx7("div", { className: loader(), children: /* @__PURE__ */ jsx7(Spinner, { size: "lg", label }) });
|
|
374
387
|
};
|
|
375
388
|
|
|
376
389
|
export {
|
package/dist/index.d.ts
CHANGED
|
@@ -431,9 +431,10 @@ type SpinnerVariant = "circle" | "dots" | "refresh";
|
|
|
431
431
|
interface SpinnerProps {
|
|
432
432
|
variant?: SpinnerVariant;
|
|
433
433
|
size?: Size;
|
|
434
|
+
label?: string;
|
|
434
435
|
}
|
|
435
436
|
|
|
436
|
-
declare const Spinner: ({ variant, size }: SpinnerProps) => react.JSX.Element;
|
|
437
|
+
declare const Spinner: ({ variant, size, label, }: SpinnerProps) => react.JSX.Element;
|
|
437
438
|
|
|
438
439
|
interface LoaderProps {
|
|
439
440
|
label?: string;
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
usePageStore,
|
|
13
13
|
useRouterStore,
|
|
14
14
|
useToastStore
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-O6UAZGBC.js";
|
|
16
16
|
import {
|
|
17
17
|
Error,
|
|
18
18
|
FormInput,
|
|
@@ -829,7 +829,7 @@ import Link from "next/link.js";
|
|
|
829
829
|
// core/sidebar/sidebar.styles.ts
|
|
830
830
|
import { tv as tv10 } from "tailwind-variants";
|
|
831
831
|
var sidebar = tv10({
|
|
832
|
-
base: "h-screen bg-neutral-800 text-neutral-300 flex flex-col overflow-hidden transition-all duration-200",
|
|
832
|
+
base: "h-screen bg-neutral-800 text-neutral-300 flex flex-col overflow-hidden transition-all duration-200 divide-y divide-neutral-600/50",
|
|
833
833
|
variants: {
|
|
834
834
|
collapsed: {
|
|
835
835
|
true: "w-14",
|
|
@@ -841,62 +841,52 @@ var sidebar = tv10({
|
|
|
841
841
|
}
|
|
842
842
|
});
|
|
843
843
|
var nav = tv10({
|
|
844
|
-
base: "flex-1 min-h-0 overflow-y-auto overflow-x-hidden"
|
|
844
|
+
base: "flex-1 min-h-0 overflow-y-auto overflow-x-hidden divide-y divide-neutral-600/50"
|
|
845
845
|
});
|
|
846
846
|
var header2 = tv10({
|
|
847
|
-
base: "shrink-0
|
|
847
|
+
base: "shrink-0 p-2"
|
|
848
848
|
});
|
|
849
849
|
var section = tv10({
|
|
850
|
-
base: "
|
|
850
|
+
base: "grid gap-1 p-2"
|
|
851
851
|
});
|
|
852
852
|
var item = tv10({
|
|
853
|
-
|
|
853
|
+
// [&>*+*] is the label: Text takes no className, and the icon comes first, so a link with no label has nothing to hide.
|
|
854
|
+
base: "flex items-center rounded-md transition-colors h-10 px-3 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current [&>*+*]:truncate [&>*+*]:transition-all [&>*+*]:duration-200",
|
|
854
855
|
variants: {
|
|
855
856
|
active: {
|
|
856
857
|
true: "bg-neutral-700 text-white",
|
|
857
858
|
false: "text-neutral-400 hover:bg-neutral-700/50 hover:text-white"
|
|
859
|
+
},
|
|
860
|
+
collapsed: {
|
|
861
|
+
true: "[&>*+*]:w-0 [&>*+*]:opacity-0",
|
|
862
|
+
false: "[&>*+*]:ml-2 [&>*+*]:opacity-100"
|
|
858
863
|
}
|
|
859
864
|
},
|
|
860
865
|
defaultVariants: {
|
|
861
|
-
active: false
|
|
866
|
+
active: false,
|
|
867
|
+
collapsed: false
|
|
862
868
|
}
|
|
863
869
|
});
|
|
864
|
-
var
|
|
865
|
-
base: "p-
|
|
866
|
-
});
|
|
867
|
-
var itemLabel = tv10({
|
|
868
|
-
base: "truncate transition-all duration-200",
|
|
870
|
+
var footer = tv10({
|
|
871
|
+
base: "shrink-0 h-16 p-3 flex items-center gap-3",
|
|
869
872
|
variants: {
|
|
870
873
|
collapsed: {
|
|
871
|
-
true: "
|
|
872
|
-
false: "opacity-100"
|
|
874
|
+
true: "justify-center"
|
|
873
875
|
}
|
|
874
|
-
},
|
|
875
|
-
defaultVariants: {
|
|
876
|
-
collapsed: false
|
|
877
876
|
}
|
|
878
877
|
});
|
|
879
|
-
var footer = tv10({
|
|
880
|
-
base: "shrink-0 border-t border-neutral-600/50 p-3 flex items-center gap-3 whitespace-nowrap"
|
|
881
|
-
});
|
|
882
878
|
var avatar = tv10({
|
|
883
|
-
base: "shrink-0
|
|
879
|
+
base: "shrink-0 size-8 rounded-full bg-neutral-600 text-white text-xs font-medium flex items-center justify-center"
|
|
884
880
|
});
|
|
885
881
|
var userInfo = tv10({
|
|
886
|
-
base: "flex flex-col min-w-0"
|
|
887
|
-
});
|
|
888
|
-
var userName = tv10({
|
|
889
|
-
base: "text-sm text-white truncate"
|
|
890
|
-
});
|
|
891
|
-
var userEmail = tv10({
|
|
892
|
-
base: "text-xs text-neutral-400"
|
|
882
|
+
base: "flex flex-col min-w-0 text-white [&>*]:truncate [&>*:last-child]:text-xs [&>*:last-child]:text-neutral-400"
|
|
893
883
|
});
|
|
894
884
|
var toggleButton = tv10({
|
|
895
|
-
base: "shrink-0
|
|
885
|
+
base: "shrink-0 h-14 grid p-2 [&>button]:justify-start [&>button]:px-3 [&>button]:overflow-hidden [&>button]:whitespace-nowrap"
|
|
896
886
|
});
|
|
897
887
|
|
|
898
888
|
// core/sidebar/sidebar.tsx
|
|
899
|
-
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
889
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
900
890
|
var getInitials = (name) => {
|
|
901
891
|
const parts = name.trim().split(/\s+/);
|
|
902
892
|
if (parts.length >= 2) {
|
|
@@ -917,39 +907,42 @@ var Sidebar = ({
|
|
|
917
907
|
const [collapsed, setCollapsed] = useState3(defaultCollapsed);
|
|
918
908
|
const initials = getInitials(user.name);
|
|
919
909
|
return /* @__PURE__ */ jsxs12("aside", { className: sidebar({ collapsed }), children: [
|
|
920
|
-
homeHref && /* @__PURE__ */ jsx14(
|
|
910
|
+
homeHref && /* @__PURE__ */ jsx14("div", { className: header2(), children: /* @__PURE__ */ jsxs12(
|
|
921
911
|
Link,
|
|
922
912
|
{
|
|
923
913
|
href: homeHref,
|
|
924
|
-
className:
|
|
914
|
+
className: item({ active: homeHref === activeHref, collapsed }),
|
|
925
915
|
"aria-label": homeLabel || "Home",
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
/* @__PURE__ */ jsx14(
|
|
929
|
-
|
|
916
|
+
...homeHref === activeHref && { "aria-current": "page" },
|
|
917
|
+
children: [
|
|
918
|
+
/* @__PURE__ */ jsx14(Icon, { name: "Home" }),
|
|
919
|
+
homeLabel && /* @__PURE__ */ jsx14(Text, { as: "span", variant: "caption", children: homeLabel })
|
|
920
|
+
]
|
|
930
921
|
}
|
|
931
|
-
),
|
|
922
|
+
) }),
|
|
932
923
|
/* @__PURE__ */ jsx14("nav", { "aria-label": "Main navigation", className: nav(), children: sections.map((sectionData, i) => /* @__PURE__ */ jsx14("div", { className: section(), children: sectionData.items.map((sidebarItem) => {
|
|
933
924
|
const isActive = sidebarItem.href === activeHref;
|
|
934
925
|
return /* @__PURE__ */ jsxs12(
|
|
935
926
|
Link,
|
|
936
927
|
{
|
|
937
928
|
href: sidebarItem.href,
|
|
938
|
-
className: item({ active: isActive }),
|
|
929
|
+
className: item({ active: isActive, collapsed }),
|
|
939
930
|
...isActive && { "aria-current": "page" },
|
|
940
931
|
children: [
|
|
941
|
-
/* @__PURE__ */ jsx14(
|
|
942
|
-
/* @__PURE__ */ jsx14(
|
|
932
|
+
/* @__PURE__ */ jsx14(Icon, { name: sidebarItem.icon }),
|
|
933
|
+
/* @__PURE__ */ jsx14(Text, { as: "span", variant: "caption", children: sidebarItem.label })
|
|
943
934
|
]
|
|
944
935
|
},
|
|
945
936
|
sidebarItem.href
|
|
946
937
|
);
|
|
947
938
|
}) }, i)) }),
|
|
948
|
-
/* @__PURE__ */ jsxs12("div", { className: footer(), children: [
|
|
949
|
-
/* @__PURE__ */
|
|
950
|
-
|
|
951
|
-
/* @__PURE__ */
|
|
952
|
-
|
|
939
|
+
/* @__PURE__ */ jsxs12("div", { className: footer({ collapsed }), children: [
|
|
940
|
+
!collapsed && /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
941
|
+
/* @__PURE__ */ jsx14("div", { "aria-hidden": "true", className: avatar(), children: initials }),
|
|
942
|
+
/* @__PURE__ */ jsxs12("div", { className: userInfo(), children: [
|
|
943
|
+
/* @__PURE__ */ jsx14(Text, { as: "span", variant: "caption", children: user.name }),
|
|
944
|
+
/* @__PURE__ */ jsx14(Text, { as: "span", variant: "caption", children: user.email })
|
|
945
|
+
] })
|
|
953
946
|
] }),
|
|
954
947
|
/* @__PURE__ */ jsx14(
|
|
955
948
|
Button,
|
|
@@ -964,11 +957,12 @@ var Sidebar = ({
|
|
|
964
957
|
/* @__PURE__ */ jsx14("div", { className: toggleButton(), children: /* @__PURE__ */ jsx14(
|
|
965
958
|
Button,
|
|
966
959
|
{
|
|
960
|
+
variant: "default",
|
|
967
961
|
color: "ghost",
|
|
968
962
|
icon: collapsed ? "ChevronRight" : "ChevronLeft",
|
|
969
|
-
"aria-label": collapsed ? "Expand sidebar" :
|
|
963
|
+
"aria-label": collapsed ? "Expand sidebar" : void 0,
|
|
970
964
|
onClick: () => setCollapsed(!collapsed),
|
|
971
|
-
children: collapseLabel
|
|
965
|
+
children: collapsed ? void 0 : collapseLabel
|
|
972
966
|
}
|
|
973
967
|
) })
|
|
974
968
|
] });
|
package/dist/next/index.js
CHANGED