@askrjs/themes 0.0.2 → 0.0.3
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/dist/navbar/navbar.js
CHANGED
|
@@ -7,6 +7,28 @@ import { Link } from "@askrjs/askr/router";
|
|
|
7
7
|
function navItemClasses(variant, className) {
|
|
8
8
|
return classes("navbar-item", variant === "icon" && "navbar-item-icon", className);
|
|
9
9
|
}
|
|
10
|
+
function normalizePathname(pathname) {
|
|
11
|
+
return pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
|
12
|
+
}
|
|
13
|
+
function getCurrentPathname() {
|
|
14
|
+
if (typeof window === "undefined") return null;
|
|
15
|
+
return normalizePathname(window.location.pathname || "/");
|
|
16
|
+
}
|
|
17
|
+
function resolveNavLinkPathname(href) {
|
|
18
|
+
const baseHref = typeof window !== "undefined" ? window.location.href : "http://localhost/";
|
|
19
|
+
const baseOrigin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
20
|
+
try {
|
|
21
|
+
const target = new URL(href, baseHref);
|
|
22
|
+
if (target.origin !== baseOrigin) return null;
|
|
23
|
+
return normalizePathname(target.pathname);
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isActiveNavLink(currentPathname, targetPathname) {
|
|
29
|
+
if (targetPathname === "/") return currentPathname === "/";
|
|
30
|
+
return currentPathname === targetPathname || currentPathname.startsWith(`${targetPathname}/`);
|
|
31
|
+
}
|
|
10
32
|
function Navbar(props) {
|
|
11
33
|
const { children, ref, class: className, ...rest } = props;
|
|
12
34
|
return /* @__PURE__ */ jsx("nav", {
|
|
@@ -56,14 +78,22 @@ function NavItem(props) {
|
|
|
56
78
|
});
|
|
57
79
|
}
|
|
58
80
|
function NavLink(props) {
|
|
59
|
-
const { children, ref, class: className, variant = "default", ...rest } = props;
|
|
81
|
+
const { children, href, ref, class: className, variant = "default", ...rest } = props;
|
|
82
|
+
const currentPathname = getCurrentPathname();
|
|
83
|
+
const targetPathname = resolveNavLinkPathname(href);
|
|
84
|
+
const isActive = currentPathname !== null && targetPathname !== null && isActiveNavLink(currentPathname, targetPathname);
|
|
85
|
+
const linkProps = mergeProps(rest, {
|
|
86
|
+
ref,
|
|
87
|
+
class: navItemClasses(variant, className),
|
|
88
|
+
"data-slot": "nav-link",
|
|
89
|
+
"data-variant": variant
|
|
90
|
+
});
|
|
60
91
|
return /* @__PURE__ */ jsx(Link, {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"data-
|
|
65
|
-
|
|
66
|
-
}),
|
|
92
|
+
href,
|
|
93
|
+
...isActive ? mergeProps({
|
|
94
|
+
"aria-current": "page",
|
|
95
|
+
"data-active": "true"
|
|
96
|
+
}, linkProps) : linkProps,
|
|
67
97
|
children
|
|
68
98
|
});
|
|
69
99
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navbar.js","names":[],"sources":["../../src/components/navbar/navbar.tsx"],"sourcesContent":["import { Link } from \"@askrjs/askr/router\";\nimport { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport type {\n NavBrandProps,\n NavGroupProps,\n NavItemAsChildProps,\n NavItemProps,\n NavItemVariant,\n NavLinkProps,\n NavbarProps,\n} from \"./navbar.types\";\nimport { classes } from \"../_internal/classes\";\n\nfunction navItemClasses(variant: NavItemVariant, className: unknown): string | undefined {\n return classes(\"navbar-item\", variant === \"icon\" && \"navbar-item-icon\", className);\n}\n\nexport function Navbar(props: NavbarProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <nav {...rest} ref={ref} class={classes(\"navbar\", className)} data-slot=\"navbar\">\n {children}\n </nav>\n );\n}\n\nexport function NavBrand(props: NavBrandProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <div {...rest} ref={ref} class={classes(\"navbar-brand\", className)} data-slot=\"navbar-brand\">\n {children}\n </div>\n );\n}\n\nexport function NavGroup(props: NavGroupProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <div {...rest} ref={ref} class={classes(\"navbar-group\", className)} data-slot=\"navbar-group\">\n {children}\n </div>\n );\n}\n\nexport function NavItem(props: NavItemProps): JSX.Element;\nexport function NavItem(props: NavItemAsChildProps): JSX.Element;\nexport function NavItem(props: NavItemProps | NavItemAsChildProps): JSX.Element {\n const { asChild, children, ref, class: className, variant = \"default\", ...rest } = props;\n\n const finalProps = mergeProps(rest, {\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-item\",\n \"data-variant\": variant,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <a {...finalProps}>{children}</a>;\n}\n\nexport function NavLink(props: NavLinkProps): JSX.Element {\n const { children, ref, class: className, variant = \"default\", ...rest } = props;\n\n const
|
|
1
|
+
{"version":3,"file":"navbar.js","names":[],"sources":["../../src/components/navbar/navbar.tsx"],"sourcesContent":["import { Link } from \"@askrjs/askr/router\";\nimport { Slot } from \"@askrjs/askr/foundations\";\nimport { mergeProps } from \"../_internal/merge-props\";\nimport type {\n NavBrandProps,\n NavGroupProps,\n NavItemAsChildProps,\n NavItemProps,\n NavItemVariant,\n NavLinkProps,\n NavbarProps,\n} from \"./navbar.types\";\nimport { classes } from \"../_internal/classes\";\n\nfunction navItemClasses(variant: NavItemVariant, className: unknown): string | undefined {\n return classes(\"navbar-item\", variant === \"icon\" && \"navbar-item-icon\", className);\n}\n\nfunction normalizePathname(pathname: string): string {\n return pathname.endsWith(\"/\") && pathname !== \"/\" ? pathname.slice(0, -1) : pathname;\n}\n\nfunction getCurrentPathname(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n return normalizePathname(window.location.pathname || \"/\");\n}\n\nfunction resolveNavLinkPathname(href: string): string | null {\n const baseHref = typeof window !== \"undefined\" ? window.location.href : \"http://localhost/\";\n const baseOrigin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n\n try {\n const target = new URL(href, baseHref);\n if (target.origin !== baseOrigin) {\n return null;\n }\n\n return normalizePathname(target.pathname);\n } catch {\n return null;\n }\n}\n\nfunction isActiveNavLink(currentPathname: string, targetPathname: string): boolean {\n if (targetPathname === \"/\") {\n return currentPathname === \"/\";\n }\n\n return currentPathname === targetPathname || currentPathname.startsWith(`${targetPathname}/`);\n}\n\nexport function Navbar(props: NavbarProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <nav {...rest} ref={ref} class={classes(\"navbar\", className)} data-slot=\"navbar\">\n {children}\n </nav>\n );\n}\n\nexport function NavBrand(props: NavBrandProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <div {...rest} ref={ref} class={classes(\"navbar-brand\", className)} data-slot=\"navbar-brand\">\n {children}\n </div>\n );\n}\n\nexport function NavGroup(props: NavGroupProps): JSX.Element {\n const { children, ref, class: className, ...rest } = props;\n\n return (\n <div {...rest} ref={ref} class={classes(\"navbar-group\", className)} data-slot=\"navbar-group\">\n {children}\n </div>\n );\n}\n\nexport function NavItem(props: NavItemProps): JSX.Element;\nexport function NavItem(props: NavItemAsChildProps): JSX.Element;\nexport function NavItem(props: NavItemProps | NavItemAsChildProps): JSX.Element {\n const { asChild, children, ref, class: className, variant = \"default\", ...rest } = props;\n\n const finalProps = mergeProps(rest, {\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-item\",\n \"data-variant\": variant,\n });\n\n if (asChild) {\n return <Slot asChild {...finalProps} children={children} />;\n }\n\n return <a {...finalProps}>{children}</a>;\n}\n\nexport function NavLink(props: NavLinkProps): JSX.Element {\n const { children, href, ref, class: className, variant = \"default\", ...rest } = props;\n const currentPathname = getCurrentPathname();\n const targetPathname = resolveNavLinkPathname(href);\n const isActive =\n currentPathname !== null &&\n targetPathname !== null &&\n isActiveNavLink(currentPathname, targetPathname);\n\n const linkProps = mergeProps(rest, {\n ref,\n class: navItemClasses(variant, className),\n \"data-slot\": \"nav-link\",\n \"data-variant\": variant,\n });\n\n const finalProps = isActive\n ? mergeProps(\n {\n \"aria-current\": \"page\",\n \"data-active\": \"true\",\n },\n linkProps,\n )\n : linkProps;\n\n return (\n <Link href={href} {...finalProps}>\n {children}\n </Link>\n );\n}\n"],"mappings":";;;;;;AAcA,SAAS,eAAe,SAAyB,WAAwC;AACvF,QAAO,QAAQ,eAAe,YAAY,UAAU,oBAAoB,UAAU;;AAGpF,SAAS,kBAAkB,UAA0B;AACnD,QAAO,SAAS,SAAS,IAAI,IAAI,aAAa,MAAM,SAAS,MAAM,GAAG,GAAG,GAAG;;AAG9E,SAAS,qBAAoC;AAC3C,KAAI,OAAO,WAAW,YACpB,QAAO;AAGT,QAAO,kBAAkB,OAAO,SAAS,YAAY,IAAI;;AAG3D,SAAS,uBAAuB,MAA6B;CAC3D,MAAM,WAAW,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;CACxE,MAAM,aAAa,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAE5E,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,MAAM,SAAS;AACtC,MAAI,OAAO,WAAW,WACpB,QAAO;AAGT,SAAO,kBAAkB,OAAO,SAAS;SACnC;AACN,SAAO;;;AAIX,SAAS,gBAAgB,iBAAyB,gBAAiC;AACjF,KAAI,mBAAmB,IACrB,QAAO,oBAAoB;AAG7B,QAAO,oBAAoB,kBAAkB,gBAAgB,WAAW,GAAG,eAAe,GAAG;;AAG/F,SAAgB,OAAO,OAAiC;CACtD,MAAM,EAAE,UAAU,KAAK,OAAO,WAAW,GAAG,SAAS;AAErD,QACE,oBAAC,OAAD;EAAK,GAAI;EAAW;EAAK,OAAO,QAAQ,UAAU,UAAU;EAAE,aAAU;EACrE;EACG,CAAA;;AAIV,SAAgB,SAAS,OAAmC;CAC1D,MAAM,EAAE,UAAU,KAAK,OAAO,WAAW,GAAG,SAAS;AAErD,QACE,oBAAC,OAAD;EAAK,GAAI;EAAW;EAAK,OAAO,QAAQ,gBAAgB,UAAU;EAAE,aAAU;EAC3E;EACG,CAAA;;AAIV,SAAgB,SAAS,OAAmC;CAC1D,MAAM,EAAE,UAAU,KAAK,OAAO,WAAW,GAAG,SAAS;AAErD,QACE,oBAAC,OAAD;EAAK,GAAI;EAAW;EAAK,OAAO,QAAQ,gBAAgB,UAAU;EAAE,aAAU;EAC3E;EACG,CAAA;;AAMV,SAAgB,QAAQ,OAAwD;CAC9E,MAAM,EAAE,SAAS,UAAU,KAAK,OAAO,WAAW,UAAU,WAAW,GAAG,SAAS;CAEnF,MAAM,aAAa,WAAW,MAAM;EAClC;EACA,OAAO,eAAe,SAAS,UAAU;EACzC,aAAa;EACb,gBAAgB;EACjB,CAAC;AAEF,KAAI,QACF,QAAO,oBAAC,MAAD;EAAM,SAAA;EAAQ,GAAI;EAAsB;EAAY,CAAA;AAG7D,QAAO,oBAAC,KAAD;EAAG,GAAI;EAAa;EAAa,CAAA;;AAG1C,SAAgB,QAAQ,OAAkC;CACxD,MAAM,EAAE,UAAU,MAAM,KAAK,OAAO,WAAW,UAAU,WAAW,GAAG,SAAS;CAChF,MAAM,kBAAkB,oBAAoB;CAC5C,MAAM,iBAAiB,uBAAuB,KAAK;CACnD,MAAM,WACJ,oBAAoB,QACpB,mBAAmB,QACnB,gBAAgB,iBAAiB,eAAe;CAElD,MAAM,YAAY,WAAW,MAAM;EACjC;EACA,OAAO,eAAe,SAAS,UAAU;EACzC,aAAa;EACb,gBAAgB;EACjB,CAAC;AAYF,QACE,oBAAC,MAAD;EAAY;EAAM,GAXD,WACf,WACE;GACE,gBAAgB;GAChB,eAAe;GAChB,EACD,UACD,GACD;EAIC;EACI,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askrjs/themes",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Default theme tokens, styles, and themed layout wrappers for Askr apps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"askr",
|
|
@@ -91,8 +91,9 @@
|
|
|
91
91
|
"verify:token-contract": "node ./scripts/verify-token-contract.js",
|
|
92
92
|
"verify:responsive": "node ./scripts/verify-responsive-theme.js",
|
|
93
93
|
"verify:slots": "node ./scripts/verify-slot-coverage.js",
|
|
94
|
-
"test": "npm run test:unit && npm run test:browser",
|
|
95
|
-
"test:unit": "vp test run -c vitest.config.ts",
|
|
94
|
+
"test": "npm run test:unit && npm run test:jsdom && npm run test:browser",
|
|
95
|
+
"test:unit": "vp test run -c vitest.node.config.ts",
|
|
96
|
+
"test:jsdom": "vp test run -c vitest.jsdom.config.ts",
|
|
96
97
|
"test:browser": "vp test run -c vitest.browser.config.ts",
|
|
97
98
|
"fmt": "vp fmt .",
|
|
98
99
|
"lint": "vp lint .",
|
|
@@ -101,10 +102,10 @@
|
|
|
101
102
|
"prepublishOnly": "npm run build"
|
|
102
103
|
},
|
|
103
104
|
"devDependencies": {
|
|
104
|
-
"@askrjs/askr": "^0.0.
|
|
105
|
-
"@askrjs/ui": "^0.0.
|
|
105
|
+
"@askrjs/askr": "^0.0.34",
|
|
106
|
+
"@askrjs/ui": "^0.0.5",
|
|
106
107
|
"@askrjs/vite": "^0.0.2",
|
|
107
|
-
"@tsdown/css": "0.
|
|
108
|
+
"@tsdown/css": "0.22.0",
|
|
108
109
|
"@types/node": "^25.6.0",
|
|
109
110
|
"jsdom": "^29.1.1",
|
|
110
111
|
"playwright": "^1.59.1",
|
|
@@ -16,6 +16,42 @@ function navItemClasses(variant: NavItemVariant, className: unknown): string | u
|
|
|
16
16
|
return classes("navbar-item", variant === "icon" && "navbar-item-icon", className);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function normalizePathname(pathname: string): string {
|
|
20
|
+
return pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getCurrentPathname(): string | null {
|
|
24
|
+
if (typeof window === "undefined") {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return normalizePathname(window.location.pathname || "/");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveNavLinkPathname(href: string): string | null {
|
|
32
|
+
const baseHref = typeof window !== "undefined" ? window.location.href : "http://localhost/";
|
|
33
|
+
const baseOrigin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const target = new URL(href, baseHref);
|
|
37
|
+
if (target.origin !== baseOrigin) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return normalizePathname(target.pathname);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isActiveNavLink(currentPathname: string, targetPathname: string): boolean {
|
|
48
|
+
if (targetPathname === "/") {
|
|
49
|
+
return currentPathname === "/";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return currentPathname === targetPathname || currentPathname.startsWith(`${targetPathname}/`);
|
|
53
|
+
}
|
|
54
|
+
|
|
19
55
|
export function Navbar(props: NavbarProps): JSX.Element {
|
|
20
56
|
const { children, ref, class: className, ...rest } = props;
|
|
21
57
|
|
|
@@ -66,14 +102,34 @@ export function NavItem(props: NavItemProps | NavItemAsChildProps): JSX.Element
|
|
|
66
102
|
}
|
|
67
103
|
|
|
68
104
|
export function NavLink(props: NavLinkProps): JSX.Element {
|
|
69
|
-
const { children, ref, class: className, variant = "default", ...rest } = props;
|
|
105
|
+
const { children, href, ref, class: className, variant = "default", ...rest } = props;
|
|
106
|
+
const currentPathname = getCurrentPathname();
|
|
107
|
+
const targetPathname = resolveNavLinkPathname(href);
|
|
108
|
+
const isActive =
|
|
109
|
+
currentPathname !== null &&
|
|
110
|
+
targetPathname !== null &&
|
|
111
|
+
isActiveNavLink(currentPathname, targetPathname);
|
|
70
112
|
|
|
71
|
-
const
|
|
113
|
+
const linkProps = mergeProps(rest, {
|
|
72
114
|
ref,
|
|
73
115
|
class: navItemClasses(variant, className),
|
|
74
116
|
"data-slot": "nav-link",
|
|
75
117
|
"data-variant": variant,
|
|
76
118
|
});
|
|
77
119
|
|
|
78
|
-
|
|
120
|
+
const finalProps = isActive
|
|
121
|
+
? mergeProps(
|
|
122
|
+
{
|
|
123
|
+
"aria-current": "page",
|
|
124
|
+
"data-active": "true",
|
|
125
|
+
},
|
|
126
|
+
linkProps,
|
|
127
|
+
)
|
|
128
|
+
: linkProps;
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<Link href={href} {...finalProps}>
|
|
132
|
+
{children}
|
|
133
|
+
</Link>
|
|
134
|
+
);
|
|
79
135
|
}
|