@camstack/ui-library 1.2.271 → 1.2.273
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/index.cjs +44 -10
- package/dist/index.js +44 -10
- package/dist/primitives/tabs.d.ts +8 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32023,7 +32023,7 @@ function useTabsContext() {
|
|
|
32023
32023
|
if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
|
|
32024
32024
|
return ctx;
|
|
32025
32025
|
}
|
|
32026
|
-
function Tabs({ value: controlledValue, onValueChange, defaultValue = "", className, ...props }) {
|
|
32026
|
+
function Tabs({ value: controlledValue, onValueChange, defaultValue = "", appearance = "underline", className, ...props }) {
|
|
32027
32027
|
const [uncontrolledValue, setUncontrolledValue] = (0, react$1.useState)(defaultValue);
|
|
32028
32028
|
const value = controlledValue ?? uncontrolledValue;
|
|
32029
32029
|
const setValue = (0, react$1.useCallback)((next) => {
|
|
@@ -32033,7 +32033,8 @@ function Tabs({ value: controlledValue, onValueChange, defaultValue = "", classN
|
|
|
32033
32033
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabsContext.Provider, {
|
|
32034
32034
|
value: {
|
|
32035
32035
|
value,
|
|
32036
|
-
setValue
|
|
32036
|
+
setValue,
|
|
32037
|
+
appearance
|
|
32037
32038
|
},
|
|
32038
32039
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
32039
32040
|
className,
|
|
@@ -32059,14 +32060,15 @@ function Tabs({ value: controlledValue, onValueChange, defaultValue = "", classN
|
|
|
32059
32060
|
* pinned to `hidden` makes it impossible here.
|
|
32060
32061
|
*/
|
|
32061
32062
|
function TabsList({ className, ...props }) {
|
|
32063
|
+
const { appearance } = useTabsContext();
|
|
32062
32064
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
32063
32065
|
role: "tablist",
|
|
32064
|
-
className: cn("flex flex-row overflow-x-auto overflow-y-hidden border-b border-border-subtle", className),
|
|
32066
|
+
className: cn("flex flex-row overflow-x-auto overflow-y-hidden", appearance === "pills" ? "gap-1 border-b border-border-subtle py-1" : "border-b border-border-subtle", className),
|
|
32065
32067
|
...props
|
|
32066
32068
|
});
|
|
32067
32069
|
}
|
|
32068
32070
|
function TabsTrigger({ value, className, ...props }) {
|
|
32069
|
-
const { value: activeValue, setValue } = useTabsContext();
|
|
32071
|
+
const { value: activeValue, setValue, appearance } = useTabsContext();
|
|
32070
32072
|
const isActive = value === activeValue;
|
|
32071
32073
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
32072
32074
|
type: "button",
|
|
@@ -32074,7 +32076,7 @@ function TabsTrigger({ value, className, ...props }) {
|
|
|
32074
32076
|
"aria-selected": isActive,
|
|
32075
32077
|
"aria-controls": `tabpanel-${value}`,
|
|
32076
32078
|
tabIndex: isActive ? 0 : -1,
|
|
32077
|
-
className: cn("h-7 shrink-0 whitespace-nowrap text-xs px-3 transition-colors", isActive ? "border-b-2 border-primary text-foreground font-medium" : "text-foreground-muted hover:text-foreground", className),
|
|
32079
|
+
className: cn("h-7 shrink-0 whitespace-nowrap text-xs px-3 transition-colors", appearance === "pills" ? isActive ? "rounded-md bg-primary/10 font-medium text-primary" : "rounded-md text-foreground-muted hover:bg-surface-hover hover:text-foreground" : isActive ? "border-b-2 border-primary text-foreground font-medium" : "text-foreground-muted hover:text-foreground", className),
|
|
32078
32080
|
onClick: () => setValue(value),
|
|
32079
32081
|
...props
|
|
32080
32082
|
});
|
|
@@ -58419,12 +58421,23 @@ function ItemFormDialog({ open, onClose, title, icon: Icon, error, width = "lg",
|
|
|
58419
58421
|
* Tiny URL query sync for surfaces that cannot assume react-router
|
|
58420
58422
|
* (federated addon pages) or that only need a handful of params.
|
|
58421
58423
|
*
|
|
58422
|
-
* Reads on mount +
|
|
58423
|
-
*
|
|
58424
|
+
* Reads on mount + whenever the query string changes (our writes, other
|
|
58425
|
+
* hook instances, react-router `setSearchParams`, back/forward). Writes
|
|
58426
|
+
* with `history.replaceState`. Empty / null values are deleted so the URL
|
|
58427
|
+
* stays short.
|
|
58428
|
+
*
|
|
58429
|
+
* Multiple `useUrlQueryParam` mounts (and a parent reading the same key via
|
|
58430
|
+
* this hook while a child writes) must stay in sync — otherwise a Rules
|
|
58431
|
+
* area pill updates `?section=` while the Notifications header still shows
|
|
58432
|
+
* "New rule" from a stale snapshot.
|
|
58424
58433
|
*/
|
|
58434
|
+
var URL_QUERY_EVENT = "camstack:url-query";
|
|
58425
58435
|
function readParam(key) {
|
|
58426
58436
|
return new URLSearchParams(window.location.search).get(key);
|
|
58427
58437
|
}
|
|
58438
|
+
function notifyUrlQuery() {
|
|
58439
|
+
window.dispatchEvent(new Event(URL_QUERY_EVENT));
|
|
58440
|
+
}
|
|
58428
58441
|
function writeParam(key, value) {
|
|
58429
58442
|
const params = new URLSearchParams(window.location.search);
|
|
58430
58443
|
if (value === null || value === "") params.delete(key);
|
|
@@ -58433,16 +58446,37 @@ function writeParam(key, value) {
|
|
|
58433
58446
|
const url = qs ? `${window.location.pathname}?${qs}` : window.location.pathname;
|
|
58434
58447
|
window.history.replaceState(null, "", url);
|
|
58435
58448
|
}
|
|
58449
|
+
var historyPatched = false;
|
|
58450
|
+
/** So react-router (and anyone else) replaceState/pushState refresh every hook. */
|
|
58451
|
+
function ensureHistoryPatched() {
|
|
58452
|
+
if (historyPatched || typeof window === "undefined") return;
|
|
58453
|
+
historyPatched = true;
|
|
58454
|
+
const originalReplace = window.history.replaceState.bind(window.history);
|
|
58455
|
+
const originalPush = window.history.pushState.bind(window.history);
|
|
58456
|
+
window.history.replaceState = (...args) => {
|
|
58457
|
+
originalReplace(...args);
|
|
58458
|
+
notifyUrlQuery();
|
|
58459
|
+
};
|
|
58460
|
+
window.history.pushState = (...args) => {
|
|
58461
|
+
originalPush(...args);
|
|
58462
|
+
notifyUrlQuery();
|
|
58463
|
+
};
|
|
58464
|
+
}
|
|
58436
58465
|
/**
|
|
58437
58466
|
* One query param as React state. `null` means absent.
|
|
58438
58467
|
* Changing it replaces the URL without a navigation.
|
|
58439
58468
|
*/
|
|
58440
58469
|
function useUrlQueryParam(key) {
|
|
58470
|
+
ensureHistoryPatched();
|
|
58441
58471
|
const [value, setValue] = (0, react$1.useState)(() => readParam(key));
|
|
58442
58472
|
(0, react$1.useEffect)(() => {
|
|
58443
|
-
const
|
|
58444
|
-
window.addEventListener("popstate",
|
|
58445
|
-
|
|
58473
|
+
const sync = () => setValue(readParam(key));
|
|
58474
|
+
window.addEventListener("popstate", sync);
|
|
58475
|
+
window.addEventListener(URL_QUERY_EVENT, sync);
|
|
58476
|
+
return () => {
|
|
58477
|
+
window.removeEventListener("popstate", sync);
|
|
58478
|
+
window.removeEventListener(URL_QUERY_EVENT, sync);
|
|
58479
|
+
};
|
|
58446
58480
|
}, [key]);
|
|
58447
58481
|
return [value, (0, react$1.useCallback)((next) => {
|
|
58448
58482
|
writeParam(key, next);
|
package/dist/index.js
CHANGED
|
@@ -31999,7 +31999,7 @@ function useTabsContext() {
|
|
|
31999
31999
|
if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
|
|
32000
32000
|
return ctx;
|
|
32001
32001
|
}
|
|
32002
|
-
function Tabs({ value: controlledValue, onValueChange, defaultValue = "", className, ...props }) {
|
|
32002
|
+
function Tabs({ value: controlledValue, onValueChange, defaultValue = "", appearance = "underline", className, ...props }) {
|
|
32003
32003
|
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
32004
32004
|
const value = controlledValue ?? uncontrolledValue;
|
|
32005
32005
|
const setValue = useCallback((next) => {
|
|
@@ -32009,7 +32009,8 @@ function Tabs({ value: controlledValue, onValueChange, defaultValue = "", classN
|
|
|
32009
32009
|
return /* @__PURE__ */ jsx(TabsContext.Provider, {
|
|
32010
32010
|
value: {
|
|
32011
32011
|
value,
|
|
32012
|
-
setValue
|
|
32012
|
+
setValue,
|
|
32013
|
+
appearance
|
|
32013
32014
|
},
|
|
32014
32015
|
children: /* @__PURE__ */ jsx("div", {
|
|
32015
32016
|
className,
|
|
@@ -32035,14 +32036,15 @@ function Tabs({ value: controlledValue, onValueChange, defaultValue = "", classN
|
|
|
32035
32036
|
* pinned to `hidden` makes it impossible here.
|
|
32036
32037
|
*/
|
|
32037
32038
|
function TabsList({ className, ...props }) {
|
|
32039
|
+
const { appearance } = useTabsContext();
|
|
32038
32040
|
return /* @__PURE__ */ jsx("div", {
|
|
32039
32041
|
role: "tablist",
|
|
32040
|
-
className: cn("flex flex-row overflow-x-auto overflow-y-hidden border-b border-border-subtle", className),
|
|
32042
|
+
className: cn("flex flex-row overflow-x-auto overflow-y-hidden", appearance === "pills" ? "gap-1 border-b border-border-subtle py-1" : "border-b border-border-subtle", className),
|
|
32041
32043
|
...props
|
|
32042
32044
|
});
|
|
32043
32045
|
}
|
|
32044
32046
|
function TabsTrigger({ value, className, ...props }) {
|
|
32045
|
-
const { value: activeValue, setValue } = useTabsContext();
|
|
32047
|
+
const { value: activeValue, setValue, appearance } = useTabsContext();
|
|
32046
32048
|
const isActive = value === activeValue;
|
|
32047
32049
|
return /* @__PURE__ */ jsx("button", {
|
|
32048
32050
|
type: "button",
|
|
@@ -32050,7 +32052,7 @@ function TabsTrigger({ value, className, ...props }) {
|
|
|
32050
32052
|
"aria-selected": isActive,
|
|
32051
32053
|
"aria-controls": `tabpanel-${value}`,
|
|
32052
32054
|
tabIndex: isActive ? 0 : -1,
|
|
32053
|
-
className: cn("h-7 shrink-0 whitespace-nowrap text-xs px-3 transition-colors", isActive ? "border-b-2 border-primary text-foreground font-medium" : "text-foreground-muted hover:text-foreground", className),
|
|
32055
|
+
className: cn("h-7 shrink-0 whitespace-nowrap text-xs px-3 transition-colors", appearance === "pills" ? isActive ? "rounded-md bg-primary/10 font-medium text-primary" : "rounded-md text-foreground-muted hover:bg-surface-hover hover:text-foreground" : isActive ? "border-b-2 border-primary text-foreground font-medium" : "text-foreground-muted hover:text-foreground", className),
|
|
32054
32056
|
onClick: () => setValue(value),
|
|
32055
32057
|
...props
|
|
32056
32058
|
});
|
|
@@ -58395,12 +58397,23 @@ function ItemFormDialog({ open, onClose, title, icon: Icon, error, width = "lg",
|
|
|
58395
58397
|
* Tiny URL query sync for surfaces that cannot assume react-router
|
|
58396
58398
|
* (federated addon pages) or that only need a handful of params.
|
|
58397
58399
|
*
|
|
58398
|
-
* Reads on mount +
|
|
58399
|
-
*
|
|
58400
|
+
* Reads on mount + whenever the query string changes (our writes, other
|
|
58401
|
+
* hook instances, react-router `setSearchParams`, back/forward). Writes
|
|
58402
|
+
* with `history.replaceState`. Empty / null values are deleted so the URL
|
|
58403
|
+
* stays short.
|
|
58404
|
+
*
|
|
58405
|
+
* Multiple `useUrlQueryParam` mounts (and a parent reading the same key via
|
|
58406
|
+
* this hook while a child writes) must stay in sync — otherwise a Rules
|
|
58407
|
+
* area pill updates `?section=` while the Notifications header still shows
|
|
58408
|
+
* "New rule" from a stale snapshot.
|
|
58400
58409
|
*/
|
|
58410
|
+
var URL_QUERY_EVENT = "camstack:url-query";
|
|
58401
58411
|
function readParam(key) {
|
|
58402
58412
|
return new URLSearchParams(window.location.search).get(key);
|
|
58403
58413
|
}
|
|
58414
|
+
function notifyUrlQuery() {
|
|
58415
|
+
window.dispatchEvent(new Event(URL_QUERY_EVENT));
|
|
58416
|
+
}
|
|
58404
58417
|
function writeParam(key, value) {
|
|
58405
58418
|
const params = new URLSearchParams(window.location.search);
|
|
58406
58419
|
if (value === null || value === "") params.delete(key);
|
|
@@ -58409,16 +58422,37 @@ function writeParam(key, value) {
|
|
|
58409
58422
|
const url = qs ? `${window.location.pathname}?${qs}` : window.location.pathname;
|
|
58410
58423
|
window.history.replaceState(null, "", url);
|
|
58411
58424
|
}
|
|
58425
|
+
var historyPatched = false;
|
|
58426
|
+
/** So react-router (and anyone else) replaceState/pushState refresh every hook. */
|
|
58427
|
+
function ensureHistoryPatched() {
|
|
58428
|
+
if (historyPatched || typeof window === "undefined") return;
|
|
58429
|
+
historyPatched = true;
|
|
58430
|
+
const originalReplace = window.history.replaceState.bind(window.history);
|
|
58431
|
+
const originalPush = window.history.pushState.bind(window.history);
|
|
58432
|
+
window.history.replaceState = (...args) => {
|
|
58433
|
+
originalReplace(...args);
|
|
58434
|
+
notifyUrlQuery();
|
|
58435
|
+
};
|
|
58436
|
+
window.history.pushState = (...args) => {
|
|
58437
|
+
originalPush(...args);
|
|
58438
|
+
notifyUrlQuery();
|
|
58439
|
+
};
|
|
58440
|
+
}
|
|
58412
58441
|
/**
|
|
58413
58442
|
* One query param as React state. `null` means absent.
|
|
58414
58443
|
* Changing it replaces the URL without a navigation.
|
|
58415
58444
|
*/
|
|
58416
58445
|
function useUrlQueryParam(key) {
|
|
58446
|
+
ensureHistoryPatched();
|
|
58417
58447
|
const [value, setValue] = useState(() => readParam(key));
|
|
58418
58448
|
useEffect(() => {
|
|
58419
|
-
const
|
|
58420
|
-
window.addEventListener("popstate",
|
|
58421
|
-
|
|
58449
|
+
const sync = () => setValue(readParam(key));
|
|
58450
|
+
window.addEventListener("popstate", sync);
|
|
58451
|
+
window.addEventListener(URL_QUERY_EVENT, sync);
|
|
58452
|
+
return () => {
|
|
58453
|
+
window.removeEventListener("popstate", sync);
|
|
58454
|
+
window.removeEventListener(URL_QUERY_EVENT, sync);
|
|
58455
|
+
};
|
|
58422
58456
|
}, [key]);
|
|
58423
58457
|
return [value, useCallback((next) => {
|
|
58424
58458
|
writeParam(key, next);
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { type JSX, type ButtonHTMLAttributes, type HTMLAttributes } from "react";
|
|
2
|
+
export type TabsAppearance = "underline" | "pills";
|
|
2
3
|
interface TabsProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
4
|
value?: string;
|
|
4
5
|
onValueChange?: (value: string) => void;
|
|
5
6
|
defaultValue?: string;
|
|
7
|
+
/**
|
|
8
|
+
* `underline` — border-b active (default, dialog editors).
|
|
9
|
+
* `pills` — chip active fill; scrollbar sits under chips so it cannot
|
|
10
|
+
* cover a bottom underline (Rules area strip).
|
|
11
|
+
*/
|
|
12
|
+
appearance?: TabsAppearance;
|
|
6
13
|
}
|
|
7
|
-
export declare function Tabs({ value: controlledValue, onValueChange, defaultValue, className, ...props }: TabsProps): JSX.Element | null;
|
|
14
|
+
export declare function Tabs({ value: controlledValue, onValueChange, defaultValue, appearance, className, ...props }: TabsProps): JSX.Element | null;
|
|
8
15
|
/**
|
|
9
16
|
* The strip SCROLLS sideways; it never squashes and never clips.
|
|
10
17
|
*
|