@dbosoft/nextjs-uicore 1.7.0-pre.4 → 1.7.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 +48 -0
- package/package.json +5 -5
- package/src/tabs/TabsClient.tsx +75 -75
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# @dbosoft/nextjs-uicore
|
|
2
2
|
|
|
3
|
+
## 1.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Republish all packages from current main with tutorial system, tabs fixes, and surface system changes.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @dbosoft/react-uicore@1.5.1
|
|
10
|
+
|
|
11
|
+
## 1.7.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- e22306c: Surface system, config-driven types, and pluggable auth.
|
|
16
|
+
|
|
17
|
+
**Surface system**
|
|
18
|
+
- 5 surface classes: `surface-base`, `surface-alt`, `surface-recede`, `surface-wash`, `surface-bold`
|
|
19
|
+
- Flat nesting — no `child-*` indirection needed
|
|
20
|
+
- Text tokens: `text-on-primary`, `text-on-secondary`, `text-on-muted`, `text-on-brand`, `text-on-link`
|
|
21
|
+
- Dark mode uses dark blue surfaces (hue 215°) with wide lightness steps
|
|
22
|
+
- WCAG AAA validated: 10 surfaces, ~50 foreground pairings, 0 FAIL
|
|
23
|
+
- **Breaking:** Removed `child-container`, `child-zone-light`, `child-zone-dark`, `child-emphasis`, `border-child`, `bg-child-*`
|
|
24
|
+
- **Breaking:** Renamed `surface-page` → `surface-base`, `surface-page-alt` → `surface-alt`, `surface-page-recede` → `surface-recede`, `surface-brand-wash` → `surface-wash`, `surface-brand-bold` → `surface-bold`
|
|
25
|
+
|
|
26
|
+
**Tabs**
|
|
27
|
+
- Dual-mode routing (path or query parameter) with configurable param name
|
|
28
|
+
- Client-only tab switching via pushState, zero re-render tab changes
|
|
29
|
+
|
|
30
|
+
**Config-driven type system**
|
|
31
|
+
- `createSiteConfig()` infers all types from config objects — no manual type declarations
|
|
32
|
+
- **Breaking:** `createLink()` removed — use `createSiteConfig()` instead
|
|
33
|
+
- **Breaking:** `useSiteConfig()` removed — pass config as props
|
|
34
|
+
- **Breaking:** `BreadcrumbSchemaClient` / `BreadcrumbSchemaLazy` exports removed
|
|
35
|
+
- **Breaking:** `GetStartedConfig` type removed
|
|
36
|
+
|
|
37
|
+
**Pluggable auth**
|
|
38
|
+
- `authSlot` prop on `HeadNav` — consumer passes their own auth UI component
|
|
39
|
+
- Framework no longer imports `next-auth` — zero auth library dependency
|
|
40
|
+
- **Breaking:** `config.auth` removed — use `HeadNav authSlot` prop + consumer-side SessionProvider
|
|
41
|
+
- **Breaking:** `AuthAdapter`, `AuthSession`, `AuthConfig` types removed
|
|
42
|
+
|
|
43
|
+
**@dbosoft/nextjs-auth (new package)**
|
|
44
|
+
- OIDC authentication with PKCE, iron-session encrypted cookies, per-scope token caching, i18n support
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- Updated dependencies [e22306c]
|
|
49
|
+
- @dbosoft/react-uicore@1.5.0
|
|
50
|
+
|
|
3
51
|
## 1.7.0-pre.4
|
|
4
52
|
|
|
5
53
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "DEPRECATED: Use @dbosoft/react-uicore/tabs for pure React tabs and @dbosoft/nextjs-site-core/ui/tabs for Next.js integration. All other components (head, subnav, themeselector) are replaced by @dbosoft/nextjs-site-core.",
|
|
4
4
|
"deprecated": true,
|
|
5
5
|
"author": "dbosoft",
|
|
6
|
-
"version": "1.7.
|
|
6
|
+
"version": "1.7.1",
|
|
7
7
|
"sideEffects": false,
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"exports": {
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"react": "^19.0.0",
|
|
24
24
|
"react-dom": "^19.0.0",
|
|
25
25
|
"typescript": "^5.8.0",
|
|
26
|
-
"@dbosoft/typescript-config": "1.1.
|
|
27
|
-
"@dbosoft/eslint-config": "2.0.
|
|
28
|
-
"@dbosoft/web-types": "1.0.
|
|
26
|
+
"@dbosoft/typescript-config": "1.1.1",
|
|
27
|
+
"@dbosoft/eslint-config": "2.0.1",
|
|
28
|
+
"@dbosoft/web-types": "1.0.1"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@heroicons/react": ">=2.1.0",
|
|
40
40
|
"clsx": ">=2.1.0",
|
|
41
41
|
"next-themes": ">=0.4.3",
|
|
42
|
-
"@dbosoft/react-uicore": "1.5.
|
|
42
|
+
"@dbosoft/react-uicore": "1.5.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"check-types": "tsc --noEmit",
|
package/src/tabs/TabsClient.tsx
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
4
|
-
import { FC, ReactNode, forwardRef, useState } from "react";
|
|
5
|
-
import { TabGroup } from "@headlessui/react"
|
|
6
|
-
import Link from "next/link";
|
|
7
|
-
import clsx from "clsx";
|
|
8
|
-
|
|
9
|
-
export type TabConfig = {
|
|
10
|
-
name: string,
|
|
11
|
-
displayName: string
|
|
12
|
-
className?: string
|
|
13
|
-
content: ReactNode
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const createNavUrl = (index: number, tabs: string[], pathname: string, searchParams: URLSearchParams) => {
|
|
17
|
-
const lastSegment = pathname.split(`/`).pop();
|
|
18
|
-
let newPath = pathname;
|
|
19
|
-
|
|
20
|
-
if (lastSegment && tabs.includes(lastSegment)) {
|
|
21
|
-
newPath = pathname.substring(0, pathname.lastIndexOf(`/`));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const newTab = index > 0 ? tabs[index] : ``;
|
|
25
|
-
newPath = newPath + `/` + newTab;
|
|
26
|
-
|
|
27
|
-
const query = searchParams.toString();
|
|
28
|
-
|
|
29
|
-
if (query)
|
|
30
|
-
return (newPath + `?` + query);
|
|
31
|
-
else
|
|
32
|
-
return newPath;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const TabLink = forwardRef<HTMLAnchorElement, React.PropsWithChildren<{
|
|
36
|
-
index: number, tabs: string[], className: string
|
|
37
|
-
}>>((props, ref) => {
|
|
38
|
-
|
|
39
|
-
const pathname = usePathname()
|
|
40
|
-
const searchParams = useSearchParams()
|
|
41
|
-
|
|
42
|
-
return <Link prefetch={false} role="tab" {...props} className={clsx(`data-[selected]:border-secondary data-[selected]:text-link-light dark:data-[selected]:text-sky-300`,
|
|
43
|
-
`border-transparent text-on-secondary hover:border-secondary hover:text-sky-600 dark:hover:text-sky-200 `,
|
|
44
|
-
`whitespace-nowrap border-b-2 mx-3 px-2 py-2 text-base font-semibold`)} ref={ref} href={createNavUrl(props.index, props.tabs, pathname, searchParams)}
|
|
45
|
-
>
|
|
46
|
-
{props.children}
|
|
47
|
-
</Link >
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
TabLink.displayName = `TabLink`;
|
|
51
|
-
|
|
52
|
-
const TabsClient: FC<{
|
|
53
|
-
children: ReactNode,
|
|
54
|
-
initialTab: number,
|
|
55
|
-
tabs: string[]
|
|
56
|
-
}> = ({
|
|
57
|
-
children,
|
|
58
|
-
tabs,
|
|
59
|
-
initialTab
|
|
60
|
-
}) => {
|
|
61
|
-
const router = useRouter();
|
|
62
|
-
const pathname = usePathname();
|
|
63
|
-
const searchParams = useSearchParams();
|
|
64
|
-
const [selectedTab, setSelectedTab] = useState(initialTab);
|
|
65
|
-
|
|
66
|
-
return <TabGroup className="text-on-primary" manual selectedIndex={selectedTab}
|
|
67
|
-
defaultIndex={initialTab} onChange={(index) => {
|
|
68
|
-
router.push(createNavUrl(index, tabs, pathname, searchParams));
|
|
69
|
-
setSelectedTab(index);
|
|
70
|
-
}}>
|
|
71
|
-
{children}
|
|
72
|
-
</TabGroup>
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export default TabsClient
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
4
|
+
import { FC, ReactNode, forwardRef, useState } from "react";
|
|
5
|
+
import { TabGroup } from "@headlessui/react"
|
|
6
|
+
import Link from "next/link";
|
|
7
|
+
import clsx from "clsx";
|
|
8
|
+
|
|
9
|
+
export type TabConfig = {
|
|
10
|
+
name: string,
|
|
11
|
+
displayName: string
|
|
12
|
+
className?: string
|
|
13
|
+
content: ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const createNavUrl = (index: number, tabs: string[], pathname: string, searchParams: URLSearchParams) => {
|
|
17
|
+
const lastSegment = pathname.split(`/`).pop();
|
|
18
|
+
let newPath = pathname;
|
|
19
|
+
|
|
20
|
+
if (lastSegment && tabs.includes(lastSegment)) {
|
|
21
|
+
newPath = pathname.substring(0, pathname.lastIndexOf(`/`));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const newTab = index > 0 ? tabs[index] : ``;
|
|
25
|
+
newPath = newPath + `/` + newTab;
|
|
26
|
+
|
|
27
|
+
const query = searchParams.toString();
|
|
28
|
+
|
|
29
|
+
if (query)
|
|
30
|
+
return (newPath + `?` + query);
|
|
31
|
+
else
|
|
32
|
+
return newPath;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const TabLink = forwardRef<HTMLAnchorElement, React.PropsWithChildren<{
|
|
36
|
+
index: number, tabs: string[], className: string
|
|
37
|
+
}>>((props, ref) => {
|
|
38
|
+
|
|
39
|
+
const pathname = usePathname()
|
|
40
|
+
const searchParams = useSearchParams()
|
|
41
|
+
|
|
42
|
+
return <Link prefetch={false} role="tab" {...props} className={clsx(`data-[selected]:border-secondary data-[selected]:text-link-light dark:data-[selected]:text-sky-300`,
|
|
43
|
+
`border-transparent text-on-secondary hover:border-secondary hover:text-sky-600 dark:hover:text-sky-200 `,
|
|
44
|
+
`whitespace-nowrap border-b-2 mx-3 px-2 py-2 text-base font-semibold`)} ref={ref} href={createNavUrl(props.index, props.tabs, pathname, searchParams)}
|
|
45
|
+
>
|
|
46
|
+
{props.children}
|
|
47
|
+
</Link >
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
TabLink.displayName = `TabLink`;
|
|
51
|
+
|
|
52
|
+
const TabsClient: FC<{
|
|
53
|
+
children: ReactNode,
|
|
54
|
+
initialTab: number,
|
|
55
|
+
tabs: string[]
|
|
56
|
+
}> = ({
|
|
57
|
+
children,
|
|
58
|
+
tabs,
|
|
59
|
+
initialTab
|
|
60
|
+
}) => {
|
|
61
|
+
const router = useRouter();
|
|
62
|
+
const pathname = usePathname();
|
|
63
|
+
const searchParams = useSearchParams();
|
|
64
|
+
const [selectedTab, setSelectedTab] = useState(initialTab);
|
|
65
|
+
|
|
66
|
+
return <TabGroup className="text-on-primary" manual selectedIndex={selectedTab}
|
|
67
|
+
defaultIndex={initialTab} onChange={(index) => {
|
|
68
|
+
router.push(createNavUrl(index, tabs, pathname, searchParams));
|
|
69
|
+
setSelectedTab(index);
|
|
70
|
+
}}>
|
|
71
|
+
{children}
|
|
72
|
+
</TabGroup>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default TabsClient
|