@borisj74/bv-ds 0.1.5 → 0.1.6
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 +36 -26
- package/dist/index.js +36 -26
- package/package.json +1 -1
- package/src/components/NavAccountCard/NavAccountCard.tsx +10 -14
- package/src/components/NavItemBase/NavItemBase.tsx +7 -8
- package/src/components/NavItemDropdownBase/NavItemDropdownBase.tsx +8 -11
- package/src/components/NavMenuButton/NavMenuButton.tsx +7 -15
- package/src/components/SidebarNavigation/SidebarNavigation.tsx +10 -5
- package/src/internal/iconBox.tsx +36 -0
package/dist/index.cjs
CHANGED
|
@@ -3844,7 +3844,7 @@ var require_factoryWithTypeCheckers = __commonJS({
|
|
|
3844
3844
|
function emptyFunctionThatReturnsNull() {
|
|
3845
3845
|
return null;
|
|
3846
3846
|
}
|
|
3847
|
-
module.exports = function(
|
|
3847
|
+
module.exports = function(isValidElement13, throwOnDirectAccess) {
|
|
3848
3848
|
var ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator;
|
|
3849
3849
|
var FAUX_ITERATOR_SYMBOL = "@@iterator";
|
|
3850
3850
|
function getIteratorFn(maybeIterable) {
|
|
@@ -3972,7 +3972,7 @@ var require_factoryWithTypeCheckers = __commonJS({
|
|
|
3972
3972
|
function createElementTypeChecker() {
|
|
3973
3973
|
function validate(props, propName, componentName, location, propFullName) {
|
|
3974
3974
|
var propValue = props[propName];
|
|
3975
|
-
if (!
|
|
3975
|
+
if (!isValidElement13(propValue)) {
|
|
3976
3976
|
var propType = getPropType(propValue);
|
|
3977
3977
|
return new PropTypeError("Invalid " + location + " `" + propFullName + "` of type " + ("`" + propType + "` supplied to `" + componentName + "`, expected a single ReactElement."));
|
|
3978
3978
|
}
|
|
@@ -4160,7 +4160,7 @@ var require_factoryWithTypeCheckers = __commonJS({
|
|
|
4160
4160
|
if (Array.isArray(propValue)) {
|
|
4161
4161
|
return propValue.every(isNode);
|
|
4162
4162
|
}
|
|
4163
|
-
if (propValue === null ||
|
|
4163
|
+
if (propValue === null || isValidElement13(propValue)) {
|
|
4164
4164
|
return true;
|
|
4165
4165
|
}
|
|
4166
4166
|
var iteratorFn = getIteratorFn(propValue);
|
|
@@ -31957,7 +31957,20 @@ function MultiSelect({
|
|
|
31957
31957
|
hint && /* @__PURE__ */ jsxRuntime.jsx("span", { className: clsx_default("text-sm", invalid ? "text-text-error-primary" : "text-text-tertiary"), children: hint })
|
|
31958
31958
|
] });
|
|
31959
31959
|
}
|
|
31960
|
-
|
|
31960
|
+
function IconBox({ size = 20, className, children }) {
|
|
31961
|
+
const icon = React28.isValidElement(children) ? React28.cloneElement(children, {
|
|
31962
|
+
viewBox: children.props.viewBox ?? "0 0 24 24",
|
|
31963
|
+
className: clsx_default("w-full h-full", children.props.className)
|
|
31964
|
+
}) : children;
|
|
31965
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
31966
|
+
"span",
|
|
31967
|
+
{
|
|
31968
|
+
className: clsx_default("relative flex shrink-0 items-center justify-center", className),
|
|
31969
|
+
style: { width: size, height: size },
|
|
31970
|
+
children: icon
|
|
31971
|
+
}
|
|
31972
|
+
);
|
|
31973
|
+
}
|
|
31961
31974
|
var LayeredAvatar = ({ src, online }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex size-10 shrink-0 rounded-full border-[0.75px] border-border-secondary-alt bg-bg-primary p-[1px] shadow-xs", children: [
|
|
31962
31975
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-full overflow-hidden rounded-full border-[0.5px] border-[rgba(0,0,0,0.16)]", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: "", className: "size-full rounded-full object-cover" }) }),
|
|
31963
31976
|
online !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -31992,7 +32005,7 @@ function NavAccountCard({
|
|
|
31992
32005
|
className,
|
|
31993
32006
|
...rest
|
|
31994
32007
|
}) {
|
|
31995
|
-
const widthClass = breakpoint === "mobile" ? "w-[256px]" : "w-[280px]";
|
|
32008
|
+
const widthClass = breakpoint === "mobile" ? "w-full max-w-[256px]" : "w-full max-w-[280px]";
|
|
31996
32009
|
const avatarNode = avatar ?? (src !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(LayeredAvatar, { src, online }) : void 0);
|
|
31997
32010
|
if (variant === "simple") {
|
|
31998
32011
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -32013,7 +32026,7 @@ function NavAccountCard({
|
|
|
32013
32026
|
onClick: onSignOut,
|
|
32014
32027
|
"aria-label": "Sign out",
|
|
32015
32028
|
className: "absolute right-0 top-[15px] flex items-center justify-center rounded-sm p-sm text-fg-quaternary transition-colors hover:text-fg-quaternary-hover",
|
|
32016
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32029
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 16, children: /* @__PURE__ */ jsxRuntime.jsx(bvDsIcons.LogOut01, {}) })
|
|
32017
32030
|
}
|
|
32018
32031
|
)
|
|
32019
32032
|
]
|
|
@@ -32036,7 +32049,7 @@ function NavAccountCard({
|
|
|
32036
32049
|
"absolute right-[7px] top-[7px] flex items-center justify-center rounded-sm p-sm text-fg-quaternary",
|
|
32037
32050
|
open && "bg-bg-primary-hover"
|
|
32038
32051
|
),
|
|
32039
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
32052
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 16, children: /* @__PURE__ */ jsxRuntime.jsx(bvDsIcons.ChevronSelectorVertical, {}) })
|
|
32040
32053
|
}
|
|
32041
32054
|
)
|
|
32042
32055
|
]
|
|
@@ -32193,7 +32206,7 @@ function NavItemBase({
|
|
|
32193
32206
|
{
|
|
32194
32207
|
type,
|
|
32195
32208
|
className: clsx_default(
|
|
32196
|
-
"flex w-
|
|
32209
|
+
"flex w-full items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
32197
32210
|
className
|
|
32198
32211
|
),
|
|
32199
32212
|
...rest,
|
|
@@ -32207,11 +32220,11 @@ function NavItemBase({
|
|
|
32207
32220
|
children: [
|
|
32208
32221
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-md", children: [
|
|
32209
32222
|
dot && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-2 shrink-0 rounded-full bg-fg-success-secondary" }),
|
|
32210
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32223
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 20, className: "text-fg-quaternary", children: icon }),
|
|
32211
32224
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left text-sm font-semibold text-text-secondary", children: label })
|
|
32212
32225
|
] }),
|
|
32213
32226
|
badge != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 rounded-full border border-utility-neutral-200 bg-utility-neutral-50 px-md py-xxs text-xs font-medium text-utility-neutral-700", children: badge }),
|
|
32214
|
-
trailingChevron && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32227
|
+
trailingChevron && /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 16, className: "text-fg-quaternary", children: /* @__PURE__ */ jsxRuntime.jsx(bvDsIcons.ChevronDown, {}) })
|
|
32215
32228
|
]
|
|
32216
32229
|
}
|
|
32217
32230
|
)
|
|
@@ -32229,13 +32242,13 @@ function NavItemDropdownBase({
|
|
|
32229
32242
|
type = "button",
|
|
32230
32243
|
...rest
|
|
32231
32244
|
}) {
|
|
32232
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx_default("flex w-
|
|
32245
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx_default("flex w-full flex-col", className), children: [
|
|
32233
32246
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32234
32247
|
"button",
|
|
32235
32248
|
{
|
|
32236
32249
|
type,
|
|
32237
32250
|
onClick: onToggle,
|
|
32238
|
-
className: "flex items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
32251
|
+
className: "flex w-full items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
32239
32252
|
...rest,
|
|
32240
32253
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32241
32254
|
"div",
|
|
@@ -32246,15 +32259,10 @@ function NavItemDropdownBase({
|
|
|
32246
32259
|
),
|
|
32247
32260
|
children: [
|
|
32248
32261
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-md", children: [
|
|
32249
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32262
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 20, className: "text-fg-quaternary", children: icon }),
|
|
32250
32263
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-left text-sm font-semibold text-text-secondary", children: label })
|
|
32251
32264
|
] }),
|
|
32252
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
32253
|
-
bvDsIcons.ChevronDown,
|
|
32254
|
-
{
|
|
32255
|
-
className: clsx_default("w-full h-full transition-transform", open && "rotate-180")
|
|
32256
|
-
}
|
|
32257
|
-
) }) })
|
|
32265
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 16, className: "text-fg-quaternary", children: /* @__PURE__ */ jsxRuntime.jsx(bvDsIcons.ChevronDown, { className: clsx_default("transition-transform", open && "rotate-180") }) })
|
|
32258
32266
|
]
|
|
32259
32267
|
}
|
|
32260
32268
|
)
|
|
@@ -32263,7 +32271,6 @@ function NavItemDropdownBase({
|
|
|
32263
32271
|
open && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col pb-xs", children })
|
|
32264
32272
|
] });
|
|
32265
32273
|
}
|
|
32266
|
-
var IconBox = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "overflow-clip relative shrink-0 size-[20px] flex items-center justify-center", children });
|
|
32267
32274
|
function NavMenuButton({
|
|
32268
32275
|
opened = false,
|
|
32269
32276
|
className,
|
|
@@ -32282,7 +32289,7 @@ function NavMenuButton({
|
|
|
32282
32289
|
className
|
|
32283
32290
|
),
|
|
32284
32291
|
...rest,
|
|
32285
|
-
children: opened ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
32292
|
+
children: opened ? /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 20, className: "opacity-70", children: /* @__PURE__ */ jsxRuntime.jsx(bvDsIcons.XClose, {}) }) : /* @__PURE__ */ jsxRuntime.jsx(IconBox, { size: 20, children: /* @__PURE__ */ jsxRuntime.jsx(bvDsIcons.Menu02, {}) })
|
|
32286
32293
|
}
|
|
32287
32294
|
);
|
|
32288
32295
|
}
|
|
@@ -33131,17 +33138,20 @@ function SidebarNavigation({
|
|
|
33131
33138
|
"nav",
|
|
33132
33139
|
{
|
|
33133
33140
|
className: clsx_default(
|
|
33141
|
+
// Padding is applied per-section (Figma node 1161:8593): header 20px,
|
|
33142
|
+
// nav items 16px, footer 16px/20px — not a uniform rail inset, so the
|
|
33143
|
+
// full-width nav items align to their own 16px gutter without clipping.
|
|
33134
33144
|
"flex h-full flex-col gap-2xl border-r border-border-secondary bg-bg-primary",
|
|
33135
|
-
slim ? "items-center px-md py-xl" : "
|
|
33145
|
+
slim ? "items-center px-md py-xl" : "py-xl",
|
|
33136
33146
|
WIDTH[type],
|
|
33137
33147
|
className
|
|
33138
33148
|
),
|
|
33139
33149
|
...rest,
|
|
33140
33150
|
children: [
|
|
33141
|
-
logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx_default("shrink-0", slim ? "" : "px-
|
|
33142
|
-
header && !slim && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: header }),
|
|
33143
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto", children }),
|
|
33144
|
-
footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 flex-col gap-lg", children: footer })
|
|
33151
|
+
logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx_default("shrink-0", slim ? "" : "px-2xl"), children: logo }),
|
|
33152
|
+
header && !slim && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 px-2xl", children: header }),
|
|
33153
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx_default("flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto", !slim && "px-xl"), children }),
|
|
33154
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: clsx_default("flex shrink-0 flex-col gap-lg", !slim && "px-xl"), children: footer })
|
|
33145
33155
|
]
|
|
33146
33156
|
}
|
|
33147
33157
|
);
|
package/dist/index.js
CHANGED
|
@@ -3823,7 +3823,7 @@ var require_factoryWithTypeCheckers = __commonJS({
|
|
|
3823
3823
|
function emptyFunctionThatReturnsNull() {
|
|
3824
3824
|
return null;
|
|
3825
3825
|
}
|
|
3826
|
-
module.exports = function(
|
|
3826
|
+
module.exports = function(isValidElement13, throwOnDirectAccess) {
|
|
3827
3827
|
var ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator;
|
|
3828
3828
|
var FAUX_ITERATOR_SYMBOL = "@@iterator";
|
|
3829
3829
|
function getIteratorFn(maybeIterable) {
|
|
@@ -3951,7 +3951,7 @@ var require_factoryWithTypeCheckers = __commonJS({
|
|
|
3951
3951
|
function createElementTypeChecker() {
|
|
3952
3952
|
function validate(props, propName, componentName, location, propFullName) {
|
|
3953
3953
|
var propValue = props[propName];
|
|
3954
|
-
if (!
|
|
3954
|
+
if (!isValidElement13(propValue)) {
|
|
3955
3955
|
var propType = getPropType(propValue);
|
|
3956
3956
|
return new PropTypeError("Invalid " + location + " `" + propFullName + "` of type " + ("`" + propType + "` supplied to `" + componentName + "`, expected a single ReactElement."));
|
|
3957
3957
|
}
|
|
@@ -4139,7 +4139,7 @@ var require_factoryWithTypeCheckers = __commonJS({
|
|
|
4139
4139
|
if (Array.isArray(propValue)) {
|
|
4140
4140
|
return propValue.every(isNode);
|
|
4141
4141
|
}
|
|
4142
|
-
if (propValue === null ||
|
|
4142
|
+
if (propValue === null || isValidElement13(propValue)) {
|
|
4143
4143
|
return true;
|
|
4144
4144
|
}
|
|
4145
4145
|
var iteratorFn = getIteratorFn(propValue);
|
|
@@ -31936,7 +31936,20 @@ function MultiSelect({
|
|
|
31936
31936
|
hint && /* @__PURE__ */ jsx("span", { className: clsx_default("text-sm", invalid ? "text-text-error-primary" : "text-text-tertiary"), children: hint })
|
|
31937
31937
|
] });
|
|
31938
31938
|
}
|
|
31939
|
-
|
|
31939
|
+
function IconBox({ size = 20, className, children }) {
|
|
31940
|
+
const icon = isValidElement(children) ? cloneElement(children, {
|
|
31941
|
+
viewBox: children.props.viewBox ?? "0 0 24 24",
|
|
31942
|
+
className: clsx_default("w-full h-full", children.props.className)
|
|
31943
|
+
}) : children;
|
|
31944
|
+
return /* @__PURE__ */ jsx(
|
|
31945
|
+
"span",
|
|
31946
|
+
{
|
|
31947
|
+
className: clsx_default("relative flex shrink-0 items-center justify-center", className),
|
|
31948
|
+
style: { width: size, height: size },
|
|
31949
|
+
children: icon
|
|
31950
|
+
}
|
|
31951
|
+
);
|
|
31952
|
+
}
|
|
31940
31953
|
var LayeredAvatar = ({ src, online }) => /* @__PURE__ */ jsxs("span", { className: "relative inline-flex size-10 shrink-0 rounded-full border-[0.75px] border-border-secondary-alt bg-bg-primary p-[1px] shadow-xs", children: [
|
|
31941
31954
|
/* @__PURE__ */ jsx("span", { className: "flex size-full overflow-hidden rounded-full border-[0.5px] border-[rgba(0,0,0,0.16)]", children: /* @__PURE__ */ jsx("img", { src, alt: "", className: "size-full rounded-full object-cover" }) }),
|
|
31942
31955
|
online !== void 0 && /* @__PURE__ */ jsx(
|
|
@@ -31971,7 +31984,7 @@ function NavAccountCard({
|
|
|
31971
31984
|
className,
|
|
31972
31985
|
...rest
|
|
31973
31986
|
}) {
|
|
31974
|
-
const widthClass = breakpoint === "mobile" ? "w-[256px]" : "w-[280px]";
|
|
31987
|
+
const widthClass = breakpoint === "mobile" ? "w-full max-w-[256px]" : "w-full max-w-[280px]";
|
|
31975
31988
|
const avatarNode = avatar ?? (src !== void 0 ? /* @__PURE__ */ jsx(LayeredAvatar, { src, online }) : void 0);
|
|
31976
31989
|
if (variant === "simple") {
|
|
31977
31990
|
return /* @__PURE__ */ jsxs(
|
|
@@ -31992,7 +32005,7 @@ function NavAccountCard({
|
|
|
31992
32005
|
onClick: onSignOut,
|
|
31993
32006
|
"aria-label": "Sign out",
|
|
31994
32007
|
className: "absolute right-0 top-[15px] flex items-center justify-center rounded-sm p-sm text-fg-quaternary transition-colors hover:text-fg-quaternary-hover",
|
|
31995
|
-
children: /* @__PURE__ */ jsx(
|
|
32008
|
+
children: /* @__PURE__ */ jsx(IconBox, { size: 16, children: /* @__PURE__ */ jsx(LogOut01, {}) })
|
|
31996
32009
|
}
|
|
31997
32010
|
)
|
|
31998
32011
|
]
|
|
@@ -32015,7 +32028,7 @@ function NavAccountCard({
|
|
|
32015
32028
|
"absolute right-[7px] top-[7px] flex items-center justify-center rounded-sm p-sm text-fg-quaternary",
|
|
32016
32029
|
open && "bg-bg-primary-hover"
|
|
32017
32030
|
),
|
|
32018
|
-
children: /* @__PURE__ */ jsx(
|
|
32031
|
+
children: /* @__PURE__ */ jsx(IconBox, { size: 16, children: /* @__PURE__ */ jsx(ChevronSelectorVertical, {}) })
|
|
32019
32032
|
}
|
|
32020
32033
|
)
|
|
32021
32034
|
]
|
|
@@ -32172,7 +32185,7 @@ function NavItemBase({
|
|
|
32172
32185
|
{
|
|
32173
32186
|
type,
|
|
32174
32187
|
className: clsx_default(
|
|
32175
|
-
"flex w-
|
|
32188
|
+
"flex w-full items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
32176
32189
|
className
|
|
32177
32190
|
),
|
|
32178
32191
|
...rest,
|
|
@@ -32186,11 +32199,11 @@ function NavItemBase({
|
|
|
32186
32199
|
children: [
|
|
32187
32200
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-md", children: [
|
|
32188
32201
|
dot && /* @__PURE__ */ jsx("span", { className: "size-2 shrink-0 rounded-full bg-fg-success-secondary" }),
|
|
32189
|
-
icon && /* @__PURE__ */ jsx(
|
|
32202
|
+
icon && /* @__PURE__ */ jsx(IconBox, { size: 20, className: "text-fg-quaternary", children: icon }),
|
|
32190
32203
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left text-sm font-semibold text-text-secondary", children: label })
|
|
32191
32204
|
] }),
|
|
32192
32205
|
badge != null && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full border border-utility-neutral-200 bg-utility-neutral-50 px-md py-xxs text-xs font-medium text-utility-neutral-700", children: badge }),
|
|
32193
|
-
trailingChevron && /* @__PURE__ */ jsx(
|
|
32206
|
+
trailingChevron && /* @__PURE__ */ jsx(IconBox, { size: 16, className: "text-fg-quaternary", children: /* @__PURE__ */ jsx(ChevronDown$1, {}) })
|
|
32194
32207
|
]
|
|
32195
32208
|
}
|
|
32196
32209
|
)
|
|
@@ -32208,13 +32221,13 @@ function NavItemDropdownBase({
|
|
|
32208
32221
|
type = "button",
|
|
32209
32222
|
...rest
|
|
32210
32223
|
}) {
|
|
32211
|
-
return /* @__PURE__ */ jsxs("div", { className: clsx_default("flex w-
|
|
32224
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx_default("flex w-full flex-col", className), children: [
|
|
32212
32225
|
/* @__PURE__ */ jsx(
|
|
32213
32226
|
"button",
|
|
32214
32227
|
{
|
|
32215
32228
|
type,
|
|
32216
32229
|
onClick: onToggle,
|
|
32217
|
-
className: "flex items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
32230
|
+
className: "flex w-full items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
32218
32231
|
...rest,
|
|
32219
32232
|
children: /* @__PURE__ */ jsxs(
|
|
32220
32233
|
"div",
|
|
@@ -32225,15 +32238,10 @@ function NavItemDropdownBase({
|
|
|
32225
32238
|
),
|
|
32226
32239
|
children: [
|
|
32227
32240
|
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-md", children: [
|
|
32228
|
-
icon && /* @__PURE__ */ jsx(
|
|
32241
|
+
icon && /* @__PURE__ */ jsx(IconBox, { size: 20, className: "text-fg-quaternary", children: icon }),
|
|
32229
32242
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left text-sm font-semibold text-text-secondary", children: label })
|
|
32230
32243
|
] }),
|
|
32231
|
-
/* @__PURE__ */ jsx(
|
|
32232
|
-
ChevronDown$1,
|
|
32233
|
-
{
|
|
32234
|
-
className: clsx_default("w-full h-full transition-transform", open && "rotate-180")
|
|
32235
|
-
}
|
|
32236
|
-
) }) })
|
|
32244
|
+
/* @__PURE__ */ jsx(IconBox, { size: 16, className: "text-fg-quaternary", children: /* @__PURE__ */ jsx(ChevronDown$1, { className: clsx_default("transition-transform", open && "rotate-180") }) })
|
|
32237
32245
|
]
|
|
32238
32246
|
}
|
|
32239
32247
|
)
|
|
@@ -32242,7 +32250,6 @@ function NavItemDropdownBase({
|
|
|
32242
32250
|
open && /* @__PURE__ */ jsx("div", { className: "flex flex-col pb-xs", children })
|
|
32243
32251
|
] });
|
|
32244
32252
|
}
|
|
32245
|
-
var IconBox = ({ children }) => /* @__PURE__ */ jsx("span", { className: "overflow-clip relative shrink-0 size-[20px] flex items-center justify-center", children });
|
|
32246
32253
|
function NavMenuButton({
|
|
32247
32254
|
opened = false,
|
|
32248
32255
|
className,
|
|
@@ -32261,7 +32268,7 @@ function NavMenuButton({
|
|
|
32261
32268
|
className
|
|
32262
32269
|
),
|
|
32263
32270
|
...rest,
|
|
32264
|
-
children: opened ? /* @__PURE__ */ jsx(
|
|
32271
|
+
children: opened ? /* @__PURE__ */ jsx(IconBox, { size: 20, className: "opacity-70", children: /* @__PURE__ */ jsx(XClose$1, {}) }) : /* @__PURE__ */ jsx(IconBox, { size: 20, children: /* @__PURE__ */ jsx(Menu02, {}) })
|
|
32265
32272
|
}
|
|
32266
32273
|
);
|
|
32267
32274
|
}
|
|
@@ -33110,17 +33117,20 @@ function SidebarNavigation({
|
|
|
33110
33117
|
"nav",
|
|
33111
33118
|
{
|
|
33112
33119
|
className: clsx_default(
|
|
33120
|
+
// Padding is applied per-section (Figma node 1161:8593): header 20px,
|
|
33121
|
+
// nav items 16px, footer 16px/20px — not a uniform rail inset, so the
|
|
33122
|
+
// full-width nav items align to their own 16px gutter without clipping.
|
|
33113
33123
|
"flex h-full flex-col gap-2xl border-r border-border-secondary bg-bg-primary",
|
|
33114
|
-
slim ? "items-center px-md py-xl" : "
|
|
33124
|
+
slim ? "items-center px-md py-xl" : "py-xl",
|
|
33115
33125
|
WIDTH[type],
|
|
33116
33126
|
className
|
|
33117
33127
|
),
|
|
33118
33128
|
...rest,
|
|
33119
33129
|
children: [
|
|
33120
|
-
logo && /* @__PURE__ */ jsx("div", { className: clsx_default("shrink-0", slim ? "" : "px-
|
|
33121
|
-
header && !slim && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: header }),
|
|
33122
|
-
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto", children }),
|
|
33123
|
-
footer && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-col gap-lg", children: footer })
|
|
33130
|
+
logo && /* @__PURE__ */ jsx("div", { className: clsx_default("shrink-0", slim ? "" : "px-2xl"), children: logo }),
|
|
33131
|
+
header && !slim && /* @__PURE__ */ jsx("div", { className: "shrink-0 px-2xl", children: header }),
|
|
33132
|
+
/* @__PURE__ */ jsx("div", { className: clsx_default("flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto", !slim && "px-xl"), children }),
|
|
33133
|
+
footer && /* @__PURE__ */ jsx("div", { className: clsx_default("flex shrink-0 flex-col gap-lg", !slim && "px-xl"), children: footer })
|
|
33124
33134
|
]
|
|
33125
33135
|
}
|
|
33126
33136
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type HTMLAttributes, type ReactNode } from "react";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { ChevronSelectorVertical, LogOut01 } from "@borisj74/bv-ds-icons";
|
|
4
|
+
import { IconBox } from "../../internal/iconBox";
|
|
4
5
|
|
|
5
6
|
export type NavAccountCardVariant = "simple" | "card";
|
|
6
7
|
export type NavAccountCardBreakpoint = "desktop" | "mobile";
|
|
@@ -32,13 +33,6 @@ export interface NavAccountCardProps
|
|
|
32
33
|
menu?: ReactNode;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
// 16px icon container (Figma nav account card).
|
|
36
|
-
const IconBox16 = ({ children }: { children: ReactNode }) => (
|
|
37
|
-
<span className="overflow-clip relative shrink-0 size-[16px] flex items-center justify-center">
|
|
38
|
-
{children}
|
|
39
|
-
</span>
|
|
40
|
-
);
|
|
41
|
-
|
|
42
36
|
/**
|
|
43
37
|
* Layered avatar treatment from Figma (node 7891:87996): white outer ring +
|
|
44
38
|
* inner hairline border + status dot. `border-[rgba(0,0,0,0.16)]` is a one-off
|
|
@@ -97,7 +91,9 @@ export function NavAccountCard({
|
|
|
97
91
|
className,
|
|
98
92
|
...rest
|
|
99
93
|
}: NavAccountCardProps) {
|
|
100
|
-
|
|
94
|
+
// Fill the container (e.g. a padded sidebar footer) but cap at the Figma
|
|
95
|
+
// standalone width so it doesn't stretch unbounded outside a sidebar.
|
|
96
|
+
const widthClass = breakpoint === "mobile" ? "w-full max-w-[256px]" : "w-full max-w-[280px]";
|
|
101
97
|
const avatarNode = avatar ?? (src !== undefined ? <LayeredAvatar src={src} online={online} /> : undefined);
|
|
102
98
|
|
|
103
99
|
if (variant === "simple") {
|
|
@@ -117,9 +113,9 @@ export function NavAccountCard({
|
|
|
117
113
|
aria-label="Sign out"
|
|
118
114
|
className="absolute right-0 top-[15px] flex items-center justify-center rounded-sm p-sm text-fg-quaternary transition-colors hover:text-fg-quaternary-hover"
|
|
119
115
|
>
|
|
120
|
-
<
|
|
121
|
-
<LogOut01
|
|
122
|
-
</
|
|
116
|
+
<IconBox size={16}>
|
|
117
|
+
<LogOut01 />
|
|
118
|
+
</IconBox>
|
|
123
119
|
</button>
|
|
124
120
|
</div>
|
|
125
121
|
);
|
|
@@ -139,9 +135,9 @@ export function NavAccountCard({
|
|
|
139
135
|
open && "bg-bg-primary-hover",
|
|
140
136
|
)}
|
|
141
137
|
>
|
|
142
|
-
<
|
|
143
|
-
<ChevronSelectorVertical
|
|
144
|
-
</
|
|
138
|
+
<IconBox size={16}>
|
|
139
|
+
<ChevronSelectorVertical />
|
|
140
|
+
</IconBox>
|
|
145
141
|
</span>
|
|
146
142
|
</button>
|
|
147
143
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ButtonHTMLAttributes, type ReactNode } from "react";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { ChevronDown } from "@borisj74/bv-ds-icons";
|
|
4
|
+
import { IconBox } from "../../internal/iconBox";
|
|
4
5
|
|
|
5
6
|
export interface NavItemBaseProps
|
|
6
7
|
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
|
|
@@ -36,7 +37,7 @@ export function NavItemBase({
|
|
|
36
37
|
<button
|
|
37
38
|
type={type}
|
|
38
39
|
className={clsx(
|
|
39
|
-
"flex w-
|
|
40
|
+
"flex w-full items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
|
|
40
41
|
className,
|
|
41
42
|
)}
|
|
42
43
|
{...rest}
|
|
@@ -50,9 +51,9 @@ export function NavItemBase({
|
|
|
50
51
|
<div className="flex min-w-0 flex-1 items-center gap-md">
|
|
51
52
|
{dot && <span className="size-2 shrink-0 rounded-full bg-fg-success-secondary" />}
|
|
52
53
|
{icon && (
|
|
53
|
-
<
|
|
54
|
+
<IconBox size={20} className="text-fg-quaternary">
|
|
54
55
|
{icon}
|
|
55
|
-
</
|
|
56
|
+
</IconBox>
|
|
56
57
|
)}
|
|
57
58
|
<span className="min-w-0 flex-1 truncate text-left text-sm font-semibold text-text-secondary">
|
|
58
59
|
{label}
|
|
@@ -64,11 +65,9 @@ export function NavItemBase({
|
|
|
64
65
|
</span>
|
|
65
66
|
)}
|
|
66
67
|
{trailingChevron && (
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
</span>
|
|
71
|
-
</span>
|
|
68
|
+
<IconBox size={16} className="text-fg-quaternary">
|
|
69
|
+
<ChevronDown />
|
|
70
|
+
</IconBox>
|
|
72
71
|
)}
|
|
73
72
|
</div>
|
|
74
73
|
</button>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ButtonHTMLAttributes, type ReactNode } from "react";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { ChevronDown } from "@borisj74/bv-ds-icons";
|
|
4
|
+
import { IconBox } from "../../internal/iconBox";
|
|
4
5
|
|
|
5
6
|
export interface NavItemDropdownBaseProps
|
|
6
7
|
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
|
|
@@ -33,11 +34,11 @@ export function NavItemDropdownBase({
|
|
|
33
34
|
...rest
|
|
34
35
|
}: NavItemDropdownBaseProps) {
|
|
35
36
|
return (
|
|
36
|
-
<div className={clsx("flex w-
|
|
37
|
+
<div className={clsx("flex w-full flex-col", className)}>
|
|
37
38
|
<button
|
|
38
39
|
type={type}
|
|
39
40
|
onClick={onToggle}
|
|
40
|
-
className="flex items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2"
|
|
41
|
+
className="flex w-full items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2"
|
|
41
42
|
{...rest}
|
|
42
43
|
>
|
|
43
44
|
<div
|
|
@@ -48,21 +49,17 @@ export function NavItemDropdownBase({
|
|
|
48
49
|
>
|
|
49
50
|
<div className="flex min-w-0 flex-1 items-center gap-md">
|
|
50
51
|
{icon && (
|
|
51
|
-
<
|
|
52
|
+
<IconBox size={20} className="text-fg-quaternary">
|
|
52
53
|
{icon}
|
|
53
|
-
</
|
|
54
|
+
</IconBox>
|
|
54
55
|
)}
|
|
55
56
|
<span className="min-w-0 flex-1 truncate text-left text-sm font-semibold text-text-secondary">
|
|
56
57
|
{label}
|
|
57
58
|
</span>
|
|
58
59
|
</div>
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
className={clsx("w-full h-full transition-transform", open && "rotate-180")}
|
|
63
|
-
/>
|
|
64
|
-
</span>
|
|
65
|
-
</span>
|
|
60
|
+
<IconBox size={16} className="text-fg-quaternary">
|
|
61
|
+
<ChevronDown className={clsx("transition-transform", open && "rotate-180")} />
|
|
62
|
+
</IconBox>
|
|
66
63
|
</div>
|
|
67
64
|
</button>
|
|
68
65
|
{open && (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type ButtonHTMLAttributes
|
|
1
|
+
import { type ButtonHTMLAttributes } from "react";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { Menu02, XClose } from "@borisj74/bv-ds-icons";
|
|
4
|
+
import { IconBox } from "../../internal/iconBox";
|
|
4
5
|
|
|
5
6
|
export interface NavMenuButtonProps
|
|
6
7
|
extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
@@ -8,13 +9,6 @@ export interface NavMenuButtonProps
|
|
|
8
9
|
opened?: boolean;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
// 20px icon container (Figma nav menu button).
|
|
12
|
-
const IconBox = ({ children }: { children: ReactNode }) => (
|
|
13
|
-
<span className="overflow-clip relative shrink-0 size-[20px] flex items-center justify-center">
|
|
14
|
-
{children}
|
|
15
|
-
</span>
|
|
16
|
-
);
|
|
17
|
-
|
|
18
12
|
/**
|
|
19
13
|
* Hamburger / collapse toggle for the mobile header & sidebar. Shows the
|
|
20
14
|
* hamburger when closed, an x-close (dimmed) when `opened`. Brand focus ring.
|
|
@@ -38,14 +32,12 @@ export function NavMenuButton({
|
|
|
38
32
|
{...rest}
|
|
39
33
|
>
|
|
40
34
|
{opened ? (
|
|
41
|
-
<
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
</IconBox>
|
|
45
|
-
</span>
|
|
35
|
+
<IconBox size={20} className="opacity-70">
|
|
36
|
+
<XClose />
|
|
37
|
+
</IconBox>
|
|
46
38
|
) : (
|
|
47
|
-
<IconBox>
|
|
48
|
-
<Menu02
|
|
39
|
+
<IconBox size={20}>
|
|
40
|
+
<Menu02 />
|
|
49
41
|
</IconBox>
|
|
50
42
|
)}
|
|
51
43
|
</button>
|
|
@@ -62,17 +62,22 @@ export function SidebarNavigation({
|
|
|
62
62
|
const rail = (
|
|
63
63
|
<nav
|
|
64
64
|
className={clsx(
|
|
65
|
+
// Padding is applied per-section (Figma node 1161:8593): header 20px,
|
|
66
|
+
// nav items 16px, footer 16px/20px — not a uniform rail inset, so the
|
|
67
|
+
// full-width nav items align to their own 16px gutter without clipping.
|
|
65
68
|
"flex h-full flex-col gap-2xl border-r border-border-secondary bg-bg-primary",
|
|
66
|
-
slim ? "items-center px-md py-xl" : "
|
|
69
|
+
slim ? "items-center px-md py-xl" : "py-xl",
|
|
67
70
|
WIDTH[type],
|
|
68
71
|
className,
|
|
69
72
|
)}
|
|
70
73
|
{...rest}
|
|
71
74
|
>
|
|
72
|
-
{logo && <div className={clsx("shrink-0", slim ? "" : "px-
|
|
73
|
-
{header && !slim && <div className="shrink-0">{header}</div>}
|
|
74
|
-
<div className="flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto"
|
|
75
|
-
|
|
75
|
+
{logo && <div className={clsx("shrink-0", slim ? "" : "px-2xl")}>{logo}</div>}
|
|
76
|
+
{header && !slim && <div className="shrink-0 px-2xl">{header}</div>}
|
|
77
|
+
<div className={clsx("flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto", !slim && "px-xl")}>
|
|
78
|
+
{children}
|
|
79
|
+
</div>
|
|
80
|
+
{footer && <div className={clsx("flex shrink-0 flex-col gap-lg", !slim && "px-xl")}>{footer}</div>}
|
|
76
81
|
</nav>
|
|
77
82
|
);
|
|
78
83
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cloneElement, isValidElement, type ReactElement, type ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface IconBoxProps {
|
|
5
|
+
/** Box size in px (Figma: 20 for nav icons, 16 for trailing/chevron icons). */
|
|
6
|
+
size?: 16 | 20 | 24;
|
|
7
|
+
className?: string;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sizes an icon to an exact px box and makes it scale correctly.
|
|
13
|
+
*
|
|
14
|
+
* The `@borisj74/bv-ds-icons` package (v0.1.0) ships SVGs with `width="1em"`
|
|
15
|
+
* and **no `viewBox`**, so a 24-unit glyph can't scale into a smaller box and
|
|
16
|
+
* its edges get cropped. We inject `viewBox="0 0 24 24"` (the Untitled UI grid)
|
|
17
|
+
* and `w-full h-full` onto the icon element so it scales into the box cleanly —
|
|
18
|
+
* no `overflow-clip` cropping. Icons inherit `currentColor`.
|
|
19
|
+
*/
|
|
20
|
+
export function IconBox({ size = 20, className, children }: IconBoxProps) {
|
|
21
|
+
const icon = isValidElement(children)
|
|
22
|
+
? cloneElement(children as ReactElement<{ viewBox?: string; className?: string }>, {
|
|
23
|
+
viewBox: (children as ReactElement<{ viewBox?: string }>).props.viewBox ?? "0 0 24 24",
|
|
24
|
+
className: clsx("w-full h-full", (children as ReactElement<{ className?: string }>).props.className),
|
|
25
|
+
})
|
|
26
|
+
: children;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<span
|
|
30
|
+
className={clsx("relative flex shrink-0 items-center justify-center", className)}
|
|
31
|
+
style={{ width: size, height: size }}
|
|
32
|
+
>
|
|
33
|
+
{icon}
|
|
34
|
+
</span>
|
|
35
|
+
);
|
|
36
|
+
}
|