@1e99/components 0.2.1 → 0.2.2
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.d.ts +3 -1
- package/dist/index.js +14 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,9 @@ type SelectorRenderTriggerContext<TOption extends SelectorOption> = {
|
|
|
36
36
|
};
|
|
37
37
|
type SelectorBaseProps = {
|
|
38
38
|
label: string;
|
|
39
|
+
showTriggerIndicator?: boolean;
|
|
39
40
|
triggerAriaLabel?: string;
|
|
41
|
+
triggerClassName?: string;
|
|
40
42
|
value: string;
|
|
41
43
|
};
|
|
42
44
|
type SelectorProps<TOption extends SelectorOption = SelectorOption> = SelectorBaseProps & {
|
|
@@ -47,7 +49,7 @@ type SelectorProps<TOption extends SelectorOption = SelectorOption> = SelectorBa
|
|
|
47
49
|
renderTrigger?: (context: SelectorRenderTriggerContext<TOption>) => ReactNode;
|
|
48
50
|
whiteSurface?: boolean;
|
|
49
51
|
};
|
|
50
|
-
declare function Selector<TOption extends SelectorOption = SelectorOption>({ density, label, onValueChange, options, renderOption, renderTrigger, triggerAriaLabel, value, whiteSurface, }: SelectorProps<TOption>): react.JSX.Element;
|
|
52
|
+
declare function Selector<TOption extends SelectorOption = SelectorOption>({ density, label, onValueChange, options, renderOption, renderTrigger, showTriggerIndicator, triggerAriaLabel, triggerClassName, value, whiteSurface, }: SelectorProps<TOption>): react.JSX.Element;
|
|
51
53
|
|
|
52
54
|
type NavbarItem = {
|
|
53
55
|
href: string;
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,9 @@ function SelectorTrigger({
|
|
|
51
51
|
optionListId,
|
|
52
52
|
renderTrigger,
|
|
53
53
|
selectedOption,
|
|
54
|
+
showTriggerIndicator,
|
|
54
55
|
triggerAriaLabel,
|
|
56
|
+
triggerClassName,
|
|
55
57
|
value
|
|
56
58
|
}) {
|
|
57
59
|
const triggerContent = renderTrigger?.({ selectedOption, value }) ?? selectedOption?.label ?? value;
|
|
@@ -61,18 +63,18 @@ function SelectorTrigger({
|
|
|
61
63
|
"aria-controls": optionListId,
|
|
62
64
|
"aria-expanded": isOpen,
|
|
63
65
|
"aria-label": triggerAriaLabel,
|
|
64
|
-
className: `${standardTriggerClassName} ${densityClassName}`,
|
|
66
|
+
className: triggerClassName ?? `${standardTriggerClassName} ${densityClassName}`,
|
|
65
67
|
onClick,
|
|
66
68
|
type: "button",
|
|
67
69
|
children: [
|
|
68
70
|
/* @__PURE__ */ jsx2("span", { children: triggerContent }),
|
|
69
|
-
/* @__PURE__ */ jsx2(
|
|
71
|
+
showTriggerIndicator ? /* @__PURE__ */ jsx2(
|
|
70
72
|
LuChevronDown,
|
|
71
73
|
{
|
|
72
74
|
"aria-hidden": "true",
|
|
73
75
|
className: `selector-disclosure-arrow size-5 shrink-0 text-content-secondary transition-transform duration-200 ease-brand motion-reduce:transition-none ${isOpen ? "rotate-180" : ""}`
|
|
74
76
|
}
|
|
75
|
-
)
|
|
77
|
+
) : null
|
|
76
78
|
]
|
|
77
79
|
}
|
|
78
80
|
);
|
|
@@ -84,7 +86,9 @@ function Selector({
|
|
|
84
86
|
options,
|
|
85
87
|
renderOption,
|
|
86
88
|
renderTrigger,
|
|
89
|
+
showTriggerIndicator = true,
|
|
87
90
|
triggerAriaLabel,
|
|
91
|
+
triggerClassName,
|
|
88
92
|
value,
|
|
89
93
|
whiteSurface = false
|
|
90
94
|
}) {
|
|
@@ -137,7 +141,9 @@ function Selector({
|
|
|
137
141
|
optionListId,
|
|
138
142
|
renderTrigger,
|
|
139
143
|
selectedOption,
|
|
144
|
+
showTriggerIndicator,
|
|
140
145
|
triggerAriaLabel,
|
|
146
|
+
triggerClassName,
|
|
141
147
|
value
|
|
142
148
|
}
|
|
143
149
|
),
|
|
@@ -201,7 +207,7 @@ function AccountControl({
|
|
|
201
207
|
/* @__PURE__ */ jsx3(
|
|
202
208
|
"span",
|
|
203
209
|
{
|
|
204
|
-
className: "w-full
|
|
210
|
+
className: "w-full break-words text-ui font-semibold text-content-primary",
|
|
205
211
|
title: identity,
|
|
206
212
|
children: identity
|
|
207
213
|
}
|
|
@@ -209,7 +215,7 @@ function AccountControl({
|
|
|
209
215
|
showEmail ? /* @__PURE__ */ jsx3(
|
|
210
216
|
"span",
|
|
211
217
|
{
|
|
212
|
-
className: "mt-1 w-full
|
|
218
|
+
className: "mt-1 w-full break-all text-label text-content-secondary",
|
|
213
219
|
title: email ?? void 0,
|
|
214
220
|
children: email
|
|
215
221
|
}
|
|
@@ -219,18 +225,10 @@ function AccountControl({
|
|
|
219
225
|
/* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: option.label }),
|
|
220
226
|
/* @__PURE__ */ jsx3("span", { className: "sr-only", children: signOutAriaLabel })
|
|
221
227
|
] }),
|
|
222
|
-
renderTrigger: () => /* @__PURE__ */
|
|
223
|
-
|
|
224
|
-
"span",
|
|
225
|
-
{
|
|
226
|
-
"aria-hidden": "true",
|
|
227
|
-
className: "flex size-8 shrink-0 items-center justify-center rounded-full bg-brand-yellow font-data text-label font-semibold text-brand-navy-dark",
|
|
228
|
-
children: initials
|
|
229
|
-
}
|
|
230
|
-
),
|
|
231
|
-
/* @__PURE__ */ jsx3("span", { className: "text-label font-semibold md:hidden", children: menuText })
|
|
232
|
-
] }),
|
|
228
|
+
renderTrigger: () => /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: initials }),
|
|
229
|
+
showTriggerIndicator: false,
|
|
233
230
|
triggerAriaLabel: `${initials} ${menuAriaLabel}`,
|
|
231
|
+
triggerClassName: "flex size-10 cursor-pointer select-none items-center justify-center rounded-full bg-brand-yellow font-data text-label font-semibold text-brand-navy-dark transition-colors duration-200 ease-brand hover:bg-brand-yellow/85 focus-visible:outline-none focus-visible:shadow-focus",
|
|
234
232
|
value: "account"
|
|
235
233
|
}
|
|
236
234
|
);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/google-sign-in-button/google-sign-in-button.tsx","../src/components/account-control/account-control.tsx","../src/utils/get-initials.ts","../src/components/selector/selector.tsx","../src/components/navbar/navbar.tsx"],"sourcesContent":["import type {ButtonHTMLAttributes, ReactNode} from 'react';\nimport {FcGoogle} from 'react-icons/fc';\n\nexport type GoogleSignInButtonProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'children' | 'className' | 'type'\n> & {\n label: ReactNode;\n};\n\nconst buttonClassName =\n 'inline-flex min-h-12 w-full cursor-pointer items-center justify-center gap-3 rounded-control border border-border-subtle bg-surface-raised px-control-x py-control-y text-label font-semibold whitespace-nowrap text-content-primary shadow-card transition-[translate,scale,background-color] duration-200 ease-brand hover:-translate-y-0.5 hover:bg-brand-cloud active:scale-[0.97] focus-visible:outline-none focus-visible:shadow-focus disabled:cursor-wait disabled:opacity-70 motion-reduce:transform-none';\n\nexport function GoogleSignInButton(\n {label, ...buttonProps}: GoogleSignInButtonProps,\n) {\n return (\n <button {...buttonProps} className={buttonClassName} type=\"button\">\n <FcGoogle\n aria-hidden=\"true\"\n className=\"size-5 shrink-0\"\n data-testid=\"google-mark\"\n />\n {label}\n </button>\n );\n}\n","import {LuLogOut} from 'react-icons/lu';\nimport {getInitials} from '../../utils/get-initials';\nimport {Selector} from '../selector/selector';\n\nexport type AccountControlProps = {\n email?: string | null;\n fallbackIdentity: string;\n menuAriaLabel: string;\n menuText: string;\n name?: string | null;\n onSignOut: () => void;\n signOutAriaLabel: string;\n signOutText: string;\n};\n\nexport function AccountControl({\n email,\n fallbackIdentity,\n menuAriaLabel,\n menuText,\n name,\n onSignOut,\n signOutAriaLabel,\n signOutText,\n}: AccountControlProps) {\n const normalizedName = name?.trim();\n const identity = normalizedName || email || fallbackIdentity;\n const initials = getInitials(identity);\n const showEmail = Boolean(email && email !== identity);\n const options = [\n {label: identity, value: 'account'},\n {label: signOutText, value: 'sign-out'},\n ];\n\n return (\n <Selector\n label={menuText}\n onValueChange={(value) => {\n if (value === 'sign-out') {\n onSignOut();\n }\n }}\n options={options}\n renderOption={({option}) => option.value === 'account' ? (\n <span data-account-identity className=\"flex min-w-0 flex-col items-start py-1\">\n <span\n className=\"w-full truncate text-ui font-semibold text-content-primary\"\n title={identity}\n >\n {identity}\n </span>\n {showEmail ? (\n <span\n className=\"mt-1 w-full truncate text-label text-content-secondary\"\n title={email ?? undefined}\n >\n {email}\n </span>\n ) : null}\n </span>\n ) : (\n <span className=\"flex items-center gap-3\">\n <LuLogOut aria-hidden=\"true\" className=\"size-5 shrink-0\" />\n <span aria-hidden=\"true\">{option.label}</span>\n <span className=\"sr-only\">{signOutAriaLabel}</span>\n </span>\n )}\n renderTrigger={() => (\n <span className=\"flex min-w-0 items-center gap-3\">\n <span\n aria-hidden=\"true\"\n className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-brand-yellow font-data text-label font-semibold text-brand-navy-dark\"\n >\n {initials}\n </span>\n <span className=\"text-label font-semibold md:hidden\">{menuText}</span>\n </span>\n )}\n triggerAriaLabel={`${initials} ${menuAriaLabel}`}\n value=\"account\"\n />\n );\n}\n","export function getInitials(value: string) {\n const parts = value.trim().split(/\\s+/).filter(Boolean);\n const selected = parts.length > 1 ? [parts[0], parts.at(-1)!] : parts;\n\n return (\n selected\n .map((part) => Array.from(part)[0])\n .join('')\n .toUpperCase()\n .slice(0, 2) || '1'\n );\n}\n","import {type ReactNode, useEffect, useId, useRef, useState} from 'react';\nimport {LuChevronDown} from 'react-icons/lu';\n\nexport type SelectorOption = {\n label: ReactNode;\n value: string;\n};\n\nexport type SelectorDensity = 'compact' | 'compact-mobile' | 'standard';\n\nexport type SelectorRenderOptionContext<TOption extends SelectorOption> = {\n isSelected: boolean;\n option: TOption;\n select: () => void;\n};\n\nexport type SelectorRenderTriggerContext<TOption extends SelectorOption> = {\n selectedOption: TOption | undefined;\n value: string;\n};\n\ntype SelectorBaseProps = {\n label: string;\n triggerAriaLabel?: string;\n value: string;\n};\n\nexport type SelectorProps<TOption extends SelectorOption = SelectorOption> =\n SelectorBaseProps & {\n density?: SelectorDensity;\n onValueChange: (value: string) => void;\n options: readonly TOption[];\n renderOption?: (context: SelectorRenderOptionContext<TOption>) => ReactNode;\n renderTrigger?: (\n context: SelectorRenderTriggerContext<TOption>,\n ) => ReactNode;\n whiteSurface?: boolean;\n };\n\nconst standardTriggerClassName =\n 'flex w-full cursor-pointer select-none items-center justify-between rounded-control border border-border-subtle py-control-y text-label font-semibold text-content-primary shadow-card transition-colors duration-200 ease-brand hover:bg-brand-cloud focus-visible:outline-none focus-visible:shadow-focus';\n\nconst optionClassName =\n 'flex min-h-12 w-full select-none items-center rounded-control px-3 text-label font-semibold text-content-secondary transition-colors duration-200 ease-brand hover:bg-brand-cloud hover:text-content-primary focus-visible:outline-none focus-visible:shadow-focus';\n\nfunction getNavigationLayout(density: SelectorDensity) {\n if (density === 'compact') {\n return {trigger: 'h-12 gap-2', wrapper: 'w-auto'};\n }\n\n if (density === 'compact-mobile') {\n return {\n trigger: 'h-12 gap-2 px-3 md:gap-4 md:px-4 md:min-w-32',\n wrapper: 'w-auto',\n };\n }\n\n return {trigger: 'min-h-12 gap-4 px-4 md:min-w-32', wrapper: 'w-full md:w-auto'};\n}\n\nfunction SelectorTrigger<TOption extends SelectorOption>({\n densityClassName,\n isOpen,\n onClick,\n optionListId,\n renderTrigger,\n selectedOption,\n triggerAriaLabel,\n value,\n}: {\n densityClassName: string;\n isOpen: boolean;\n onClick: () => void;\n optionListId: string;\n renderTrigger?: (context: SelectorRenderTriggerContext<TOption>) => ReactNode;\n selectedOption: TOption | undefined;\n triggerAriaLabel?: string;\n value: string;\n}) {\n const triggerContent = renderTrigger?.({selectedOption, value}) ??\n selectedOption?.label ?? value;\n\n return (\n <button\n aria-controls={optionListId}\n aria-expanded={isOpen}\n aria-label={triggerAriaLabel}\n className={`${standardTriggerClassName} ${densityClassName}`}\n onClick={onClick}\n type=\"button\"\n >\n <span>{triggerContent}</span>\n <LuChevronDown\n aria-hidden=\"true\"\n className={`selector-disclosure-arrow size-5 shrink-0 text-content-secondary transition-transform duration-200 ease-brand motion-reduce:transition-none ${isOpen ? 'rotate-180' : ''}`}\n />\n </button>\n );\n}\n\nexport function Selector<TOption extends SelectorOption = SelectorOption>({\n density = 'standard',\n label,\n onValueChange,\n options,\n renderOption,\n renderTrigger,\n triggerAriaLabel,\n value,\n whiteSurface = false,\n}: SelectorProps<TOption>) {\n const [isOpen, setIsOpen] = useState(false);\n const [selectionRequest, setSelectionRequest] =\n useState<{value: string} | null>(null);\n const optionListId = useId();\n const notifiedSelectionReference = useRef<{value: string} | null>(null);\n const onValueChangeReference = useRef(onValueChange);\n const selectorReference = useRef<HTMLDivElement>(null);\n const selectedOption = options.find((option) => option.value === value);\n const layout = getNavigationLayout(density);\n const surfaceClassName = whiteSurface ? 'bg-white' : 'bg-surface-raised';\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const closeWhenPointerStartsOutside = (event: PointerEvent) => {\n const selectorElement = selectorReference.current;\n\n if (\n !selectorElement ||\n !(event.target instanceof Node) ||\n selectorElement.contains(event.target)\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n document.addEventListener('pointerdown', closeWhenPointerStartsOutside, true);\n\n return () => {\n document.removeEventListener('pointerdown', closeWhenPointerStartsOutside, true);\n };\n }, [isOpen]);\n\n useEffect(() => {\n onValueChangeReference.current = onValueChange;\n }, [onValueChange]);\n\n useEffect(() => {\n if (\n isOpen ||\n selectionRequest === null ||\n selectionRequest === notifiedSelectionReference.current\n ) {\n return;\n }\n\n notifiedSelectionReference.current = selectionRequest;\n onValueChangeReference.current(selectionRequest.value);\n }, [isOpen, selectionRequest]);\n\n const selectOption = (nextValue: string) => {\n setIsOpen(false);\n setSelectionRequest({value: nextValue});\n };\n\n return (\n <div ref={selectorReference} className={`selector-disclosure relative ${layout.wrapper}`}>\n <SelectorTrigger\n densityClassName={layout.trigger}\n isOpen={isOpen}\n onClick={() => setIsOpen((currentOpen) => !currentOpen)}\n optionListId={optionListId}\n renderTrigger={renderTrigger}\n selectedOption={selectedOption}\n triggerAriaLabel={triggerAriaLabel}\n value={value}\n />\n {isOpen ? (\n <ul\n aria-label={label}\n className={`mt-2 w-full overflow-hidden rounded-control border border-border-subtle ${surfaceClassName} p-1 shadow-float md:absolute md:top-full md:right-0 md:z-60 md:min-w-44`}\n id={optionListId}\n >\n {options.map((option) => {\n const isSelected = option.value === value;\n const select = () => selectOption(option.value);\n const optionContent =\n renderOption?.({isSelected, option, select}) ?? option.label;\n\n return (\n <li key={option.value}>\n <button\n aria-pressed={isSelected}\n className={`${optionClassName} text-left ${isSelected ? 'bg-brand-cloud text-content-primary' : ''}`}\n onClick={select}\n type=\"button\"\n >\n {optionContent}\n </button>\n </li>\n );\n })}\n </ul>\n ) : null}\n </div>\n );\n}\n","import {Fragment, type ReactNode, useId} from 'react';\nimport {LuMenu} from 'react-icons/lu';\n\nexport type NavbarItem = {\n href: string;\n label: ReactNode;\n};\n\nexport type NavbarLinkRenderer = (props: {\n children: ReactNode;\n className: string;\n href: string;\n}) => ReactNode;\n\nexport type NavbarWidth = 'content' | 'wide';\nexport type NavbarLinkTreatment = 'plain' | 'underlined';\nexport type NavbarLinkWeight = 'bold' | 'semibold';\nexport type NavbarLayer = 'above' | 'standard';\nexport type NavbarMobileNavigation = {\n actions?: ReactNode;\n menuLabel: string;\n navigationLabel: string;\n};\n\nexport type NavbarProps = {\n actions?: ReactNode;\n brand: ReactNode;\n items: readonly NavbarItem[];\n layer?: NavbarLayer;\n linkTreatment?: NavbarLinkTreatment;\n linkWeight?: NavbarLinkWeight;\n mobileNavigation?: NavbarMobileNavigation;\n navigationLabel: string;\n renderLink?: NavbarLinkRenderer;\n width?: NavbarWidth;\n};\n\nconst baseLinkClassName =\n 'text-label text-content-secondary transition-colors duration-200 ease-brand hover:text-content-primary focus-visible:rounded-control focus-visible:outline-none focus-visible:shadow-focus';\n\nconst underlinedLinkClassName =\n 'relative after:absolute after:-bottom-1.5 after:left-0 after:h-0.5 after:w-full after:origin-left after:scale-x-0 after:bg-action-primary after:transition-transform after:duration-200 after:ease-brand hover:after:scale-x-100 focus-visible:after:scale-x-100';\n\nconst mobileLinkClassName =\n 'flex min-h-12 items-center rounded-control px-3 text-label font-semibold text-content-secondary transition-colors duration-200 ease-brand hover:text-content-primary focus-visible:outline-none focus-visible:shadow-focus';\n\nexport function Navbar({\n actions,\n brand,\n items,\n layer = 'standard',\n linkTreatment = 'plain',\n linkWeight = 'semibold',\n mobileNavigation,\n navigationLabel,\n renderLink,\n width = 'content',\n}: NavbarProps) {\n const mobileNavigationReference = useId();\n const mobileNavigationId = `navbar-mobile-navigation-${mobileNavigationReference}`;\n const mobileNavigationAnchorName = `--navbar-mobile-menu-trigger-${mobileNavigationReference.replace(/[^a-zA-Z0-9_-]/g, '-')}`;\n const linkClassName = [\n baseLinkClassName,\n linkWeight === 'bold' ? 'font-bold' : 'font-semibold',\n linkTreatment === 'underlined' ? underlinedLinkClassName : '',\n ]\n .filter(Boolean)\n .join(' ');\n const containerWidthClassName = width === 'wide' ? 'max-w-7xl' : 'max-w-5xl';\n const layerClassName = layer === 'above' ? 'z-50' : 'z-40';\n const renderLinks = (className: string) =>\n items.map((item) => (\n <Fragment key={item.href}>\n {renderLink ? (\n renderLink({\n children: item.label,\n className,\n href: item.href,\n })\n ) : (\n <a className={className} href={item.href}>\n {item.label}\n </a>\n )}\n </Fragment>\n ));\n\n return (\n <header\n className={`sticky top-0 ${layerClassName} border-b border-border-subtle bg-surface-page/90 text-label font-semibold backdrop-blur-lg`}\n >\n <div\n className={`mx-auto flex min-h-20 ${containerWidthClassName} items-center justify-between gap-4 px-shell`}\n >\n <div className=\"shrink-0\">{brand}</div>\n <nav aria-label={navigationLabel} className=\"hidden items-center gap-6 lg:flex\">\n {renderLinks(linkClassName)}\n </nav>\n {actions}\n {mobileNavigation ? (\n <div className=\"relative md:hidden\">\n <button\n aria-controls={mobileNavigationId}\n aria-label={mobileNavigation.menuLabel}\n className=\"flex size-12 cursor-pointer items-center justify-center rounded-control bg-action-primary text-content-inverse shadow-card transition-[translate,scale,background-color] duration-200 ease-brand active:scale-[0.97] focus-visible:outline-none focus-visible:shadow-focus\"\n popoverTarget={mobileNavigationId}\n popoverTargetAction=\"toggle\"\n style={{anchorName: mobileNavigationAnchorName}}\n type=\"button\"\n >\n <span className=\"sr-only\">{mobileNavigation.menuLabel}</span>\n <LuMenu aria-hidden=\"true\" className=\"size-6\" />\n </button>\n <nav\n aria-label={mobileNavigation.navigationLabel}\n className=\"fixed top-[4.5rem] right-[1.25rem] m-0 w-72 rounded-card border border-border-subtle bg-surface-raised p-3 shadow-float [@supports(position-anchor:--navbar-mobile-menu-trigger)]:absolute [@supports(position-anchor:--navbar-mobile-menu-trigger)]:top-[calc(anchor(bottom)+0.5rem)] [@supports(position-anchor:--navbar-mobile-menu-trigger)]:right-auto [@supports(position-anchor:--navbar-mobile-menu-trigger)]:left-[anchor(right)] [@supports(position-anchor:--navbar-mobile-menu-trigger)]:-translate-x-full\"\n id={mobileNavigationId}\n popover=\"auto\"\n style={{positionAnchor: mobileNavigationAnchorName}}\n >\n {renderLinks(mobileLinkClassName)}\n {mobileNavigation.actions ? (\n <div className=\"mt-2 space-y-3 border-t border-border-subtle pt-3\">\n {mobileNavigation.actions}\n </div>\n ) : null}\n </nav>\n </div>\n ) : null}\n </div>\n </header>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","useId","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/google-sign-in-button/google-sign-in-button.tsx","../src/components/account-control/account-control.tsx","../src/utils/get-initials.ts","../src/components/selector/selector.tsx","../src/components/navbar/navbar.tsx"],"sourcesContent":["import type {ButtonHTMLAttributes, ReactNode} from 'react';\nimport {FcGoogle} from 'react-icons/fc';\n\nexport type GoogleSignInButtonProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'children' | 'className' | 'type'\n> & {\n label: ReactNode;\n};\n\nconst buttonClassName =\n 'inline-flex min-h-12 w-full cursor-pointer items-center justify-center gap-3 rounded-control border border-border-subtle bg-surface-raised px-control-x py-control-y text-label font-semibold whitespace-nowrap text-content-primary shadow-card transition-[translate,scale,background-color] duration-200 ease-brand hover:-translate-y-0.5 hover:bg-brand-cloud active:scale-[0.97] focus-visible:outline-none focus-visible:shadow-focus disabled:cursor-wait disabled:opacity-70 motion-reduce:transform-none';\n\nexport function GoogleSignInButton(\n {label, ...buttonProps}: GoogleSignInButtonProps,\n) {\n return (\n <button {...buttonProps} className={buttonClassName} type=\"button\">\n <FcGoogle\n aria-hidden=\"true\"\n className=\"size-5 shrink-0\"\n data-testid=\"google-mark\"\n />\n {label}\n </button>\n );\n}\n","import {LuLogOut} from 'react-icons/lu';\nimport {getInitials} from '../../utils/get-initials';\nimport {Selector} from '../selector/selector';\n\nexport type AccountControlProps = {\n email?: string | null;\n fallbackIdentity: string;\n menuAriaLabel: string;\n menuText: string;\n name?: string | null;\n onSignOut: () => void;\n signOutAriaLabel: string;\n signOutText: string;\n};\n\nexport function AccountControl({\n email,\n fallbackIdentity,\n menuAriaLabel,\n menuText,\n name,\n onSignOut,\n signOutAriaLabel,\n signOutText,\n}: AccountControlProps) {\n const normalizedName = name?.trim();\n const identity = normalizedName || email || fallbackIdentity;\n const initials = getInitials(identity);\n const showEmail = Boolean(email && email !== identity);\n const options = [\n {label: identity, value: 'account'},\n {label: signOutText, value: 'sign-out'},\n ];\n\n return (\n <Selector\n label={menuText}\n onValueChange={(value) => {\n if (value === 'sign-out') {\n onSignOut();\n }\n }}\n options={options}\n renderOption={({option}) => option.value === 'account' ? (\n <span data-account-identity className=\"flex min-w-0 flex-col items-start py-1\">\n <span\n className=\"w-full break-words text-ui font-semibold text-content-primary\"\n title={identity}\n >\n {identity}\n </span>\n {showEmail ? (\n <span\n className=\"mt-1 w-full break-all text-label text-content-secondary\"\n title={email ?? undefined}\n >\n {email}\n </span>\n ) : null}\n </span>\n ) : (\n <span className=\"flex items-center gap-3\">\n <LuLogOut aria-hidden=\"true\" className=\"size-5 shrink-0\" />\n <span aria-hidden=\"true\">{option.label}</span>\n <span className=\"sr-only\">{signOutAriaLabel}</span>\n </span>\n )}\n renderTrigger={() => (\n <span aria-hidden=\"true\">{initials}</span>\n )}\n showTriggerIndicator={false}\n triggerAriaLabel={`${initials} ${menuAriaLabel}`}\n triggerClassName=\"flex size-10 cursor-pointer select-none items-center justify-center rounded-full bg-brand-yellow font-data text-label font-semibold text-brand-navy-dark transition-colors duration-200 ease-brand hover:bg-brand-yellow/85 focus-visible:outline-none focus-visible:shadow-focus\"\n value=\"account\"\n />\n );\n}\n","export function getInitials(value: string) {\n const parts = value.trim().split(/\\s+/).filter(Boolean);\n const selected = parts.length > 1 ? [parts[0], parts.at(-1)!] : parts;\n\n return (\n selected\n .map((part) => Array.from(part)[0])\n .join('')\n .toUpperCase()\n .slice(0, 2) || '1'\n );\n}\n","import {type ReactNode, useEffect, useId, useRef, useState} from 'react';\nimport {LuChevronDown} from 'react-icons/lu';\n\nexport type SelectorOption = {\n label: ReactNode;\n value: string;\n};\n\nexport type SelectorDensity = 'compact' | 'compact-mobile' | 'standard';\n\nexport type SelectorRenderOptionContext<TOption extends SelectorOption> = {\n isSelected: boolean;\n option: TOption;\n select: () => void;\n};\n\nexport type SelectorRenderTriggerContext<TOption extends SelectorOption> = {\n selectedOption: TOption | undefined;\n value: string;\n};\n\ntype SelectorBaseProps = {\n label: string;\n showTriggerIndicator?: boolean;\n triggerAriaLabel?: string;\n triggerClassName?: string;\n value: string;\n};\n\nexport type SelectorProps<TOption extends SelectorOption = SelectorOption> =\n SelectorBaseProps & {\n density?: SelectorDensity;\n onValueChange: (value: string) => void;\n options: readonly TOption[];\n renderOption?: (context: SelectorRenderOptionContext<TOption>) => ReactNode;\n renderTrigger?: (\n context: SelectorRenderTriggerContext<TOption>,\n ) => ReactNode;\n whiteSurface?: boolean;\n };\n\nconst standardTriggerClassName =\n 'flex w-full cursor-pointer select-none items-center justify-between rounded-control border border-border-subtle py-control-y text-label font-semibold text-content-primary shadow-card transition-colors duration-200 ease-brand hover:bg-brand-cloud focus-visible:outline-none focus-visible:shadow-focus';\n\nconst optionClassName =\n 'flex min-h-12 w-full select-none items-center rounded-control px-3 text-label font-semibold text-content-secondary transition-colors duration-200 ease-brand hover:bg-brand-cloud hover:text-content-primary focus-visible:outline-none focus-visible:shadow-focus';\n\nfunction getNavigationLayout(density: SelectorDensity) {\n if (density === 'compact') {\n return {trigger: 'h-12 gap-2', wrapper: 'w-auto'};\n }\n\n if (density === 'compact-mobile') {\n return {\n trigger: 'h-12 gap-2 px-3 md:gap-4 md:px-4 md:min-w-32',\n wrapper: 'w-auto',\n };\n }\n\n return {trigger: 'min-h-12 gap-4 px-4 md:min-w-32', wrapper: 'w-full md:w-auto'};\n}\n\nfunction SelectorTrigger<TOption extends SelectorOption>({\n densityClassName,\n isOpen,\n onClick,\n optionListId,\n renderTrigger,\n selectedOption,\n showTriggerIndicator,\n triggerAriaLabel,\n triggerClassName,\n value,\n}: {\n densityClassName: string;\n isOpen: boolean;\n onClick: () => void;\n optionListId: string;\n renderTrigger?: (context: SelectorRenderTriggerContext<TOption>) => ReactNode;\n selectedOption: TOption | undefined;\n showTriggerIndicator: boolean;\n triggerAriaLabel?: string;\n triggerClassName?: string;\n value: string;\n}) {\n const triggerContent = renderTrigger?.({selectedOption, value}) ??\n selectedOption?.label ?? value;\n\n return (\n <button\n aria-controls={optionListId}\n aria-expanded={isOpen}\n aria-label={triggerAriaLabel}\n className={triggerClassName ?? `${standardTriggerClassName} ${densityClassName}`}\n onClick={onClick}\n type=\"button\"\n >\n <span>{triggerContent}</span>\n {showTriggerIndicator ? (\n <LuChevronDown\n aria-hidden=\"true\"\n className={`selector-disclosure-arrow size-5 shrink-0 text-content-secondary transition-transform duration-200 ease-brand motion-reduce:transition-none ${isOpen ? 'rotate-180' : ''}`}\n />\n ) : null}\n </button>\n );\n}\n\nexport function Selector<TOption extends SelectorOption = SelectorOption>({\n density = 'standard',\n label,\n onValueChange,\n options,\n renderOption,\n renderTrigger,\n showTriggerIndicator = true,\n triggerAriaLabel,\n triggerClassName,\n value,\n whiteSurface = false,\n}: SelectorProps<TOption>) {\n const [isOpen, setIsOpen] = useState(false);\n const [selectionRequest, setSelectionRequest] =\n useState<{value: string} | null>(null);\n const optionListId = useId();\n const notifiedSelectionReference = useRef<{value: string} | null>(null);\n const onValueChangeReference = useRef(onValueChange);\n const selectorReference = useRef<HTMLDivElement>(null);\n const selectedOption = options.find((option) => option.value === value);\n const layout = getNavigationLayout(density);\n const surfaceClassName = whiteSurface ? 'bg-white' : 'bg-surface-raised';\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const closeWhenPointerStartsOutside = (event: PointerEvent) => {\n const selectorElement = selectorReference.current;\n\n if (\n !selectorElement ||\n !(event.target instanceof Node) ||\n selectorElement.contains(event.target)\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n document.addEventListener('pointerdown', closeWhenPointerStartsOutside, true);\n\n return () => {\n document.removeEventListener('pointerdown', closeWhenPointerStartsOutside, true);\n };\n }, [isOpen]);\n\n useEffect(() => {\n onValueChangeReference.current = onValueChange;\n }, [onValueChange]);\n\n useEffect(() => {\n if (\n isOpen ||\n selectionRequest === null ||\n selectionRequest === notifiedSelectionReference.current\n ) {\n return;\n }\n\n notifiedSelectionReference.current = selectionRequest;\n onValueChangeReference.current(selectionRequest.value);\n }, [isOpen, selectionRequest]);\n\n const selectOption = (nextValue: string) => {\n setIsOpen(false);\n setSelectionRequest({value: nextValue});\n };\n\n return (\n <div ref={selectorReference} className={`selector-disclosure relative ${layout.wrapper}`}>\n <SelectorTrigger\n densityClassName={layout.trigger}\n isOpen={isOpen}\n onClick={() => setIsOpen((currentOpen) => !currentOpen)}\n optionListId={optionListId}\n renderTrigger={renderTrigger}\n selectedOption={selectedOption}\n showTriggerIndicator={showTriggerIndicator}\n triggerAriaLabel={triggerAriaLabel}\n triggerClassName={triggerClassName}\n value={value}\n />\n {isOpen ? (\n <ul\n aria-label={label}\n className={`mt-2 w-full overflow-hidden rounded-control border border-border-subtle ${surfaceClassName} p-1 shadow-float md:absolute md:top-full md:right-0 md:z-60 md:min-w-44`}\n id={optionListId}\n >\n {options.map((option) => {\n const isSelected = option.value === value;\n const select = () => selectOption(option.value);\n const optionContent =\n renderOption?.({isSelected, option, select}) ?? option.label;\n\n return (\n <li key={option.value}>\n <button\n aria-pressed={isSelected}\n className={`${optionClassName} text-left ${isSelected ? 'bg-brand-cloud text-content-primary' : ''}`}\n onClick={select}\n type=\"button\"\n >\n {optionContent}\n </button>\n </li>\n );\n })}\n </ul>\n ) : null}\n </div>\n );\n}\n","import {Fragment, type ReactNode, useId} from 'react';\nimport {LuMenu} from 'react-icons/lu';\n\nexport type NavbarItem = {\n href: string;\n label: ReactNode;\n};\n\nexport type NavbarLinkRenderer = (props: {\n children: ReactNode;\n className: string;\n href: string;\n}) => ReactNode;\n\nexport type NavbarWidth = 'content' | 'wide';\nexport type NavbarLinkTreatment = 'plain' | 'underlined';\nexport type NavbarLinkWeight = 'bold' | 'semibold';\nexport type NavbarLayer = 'above' | 'standard';\nexport type NavbarMobileNavigation = {\n actions?: ReactNode;\n menuLabel: string;\n navigationLabel: string;\n};\n\nexport type NavbarProps = {\n actions?: ReactNode;\n brand: ReactNode;\n items: readonly NavbarItem[];\n layer?: NavbarLayer;\n linkTreatment?: NavbarLinkTreatment;\n linkWeight?: NavbarLinkWeight;\n mobileNavigation?: NavbarMobileNavigation;\n navigationLabel: string;\n renderLink?: NavbarLinkRenderer;\n width?: NavbarWidth;\n};\n\nconst baseLinkClassName =\n 'text-label text-content-secondary transition-colors duration-200 ease-brand hover:text-content-primary focus-visible:rounded-control focus-visible:outline-none focus-visible:shadow-focus';\n\nconst underlinedLinkClassName =\n 'relative after:absolute after:-bottom-1.5 after:left-0 after:h-0.5 after:w-full after:origin-left after:scale-x-0 after:bg-action-primary after:transition-transform after:duration-200 after:ease-brand hover:after:scale-x-100 focus-visible:after:scale-x-100';\n\nconst mobileLinkClassName =\n 'flex min-h-12 items-center rounded-control px-3 text-label font-semibold text-content-secondary transition-colors duration-200 ease-brand hover:text-content-primary focus-visible:outline-none focus-visible:shadow-focus';\n\nexport function Navbar({\n actions,\n brand,\n items,\n layer = 'standard',\n linkTreatment = 'plain',\n linkWeight = 'semibold',\n mobileNavigation,\n navigationLabel,\n renderLink,\n width = 'content',\n}: NavbarProps) {\n const mobileNavigationReference = useId();\n const mobileNavigationId = `navbar-mobile-navigation-${mobileNavigationReference}`;\n const mobileNavigationAnchorName = `--navbar-mobile-menu-trigger-${mobileNavigationReference.replace(/[^a-zA-Z0-9_-]/g, '-')}`;\n const linkClassName = [\n baseLinkClassName,\n linkWeight === 'bold' ? 'font-bold' : 'font-semibold',\n linkTreatment === 'underlined' ? underlinedLinkClassName : '',\n ]\n .filter(Boolean)\n .join(' ');\n const containerWidthClassName = width === 'wide' ? 'max-w-7xl' : 'max-w-5xl';\n const layerClassName = layer === 'above' ? 'z-50' : 'z-40';\n const renderLinks = (className: string) =>\n items.map((item) => (\n <Fragment key={item.href}>\n {renderLink ? (\n renderLink({\n children: item.label,\n className,\n href: item.href,\n })\n ) : (\n <a className={className} href={item.href}>\n {item.label}\n </a>\n )}\n </Fragment>\n ));\n\n return (\n <header\n className={`sticky top-0 ${layerClassName} border-b border-border-subtle bg-surface-page/90 text-label font-semibold backdrop-blur-lg`}\n >\n <div\n className={`mx-auto flex min-h-20 ${containerWidthClassName} items-center justify-between gap-4 px-shell`}\n >\n <div className=\"shrink-0\">{brand}</div>\n <nav aria-label={navigationLabel} className=\"hidden items-center gap-6 lg:flex\">\n {renderLinks(linkClassName)}\n </nav>\n {actions}\n {mobileNavigation ? (\n <div className=\"relative md:hidden\">\n <button\n aria-controls={mobileNavigationId}\n aria-label={mobileNavigation.menuLabel}\n className=\"flex size-12 cursor-pointer items-center justify-center rounded-control bg-action-primary text-content-inverse shadow-card transition-[translate,scale,background-color] duration-200 ease-brand active:scale-[0.97] focus-visible:outline-none focus-visible:shadow-focus\"\n popoverTarget={mobileNavigationId}\n popoverTargetAction=\"toggle\"\n style={{anchorName: mobileNavigationAnchorName}}\n type=\"button\"\n >\n <span className=\"sr-only\">{mobileNavigation.menuLabel}</span>\n <LuMenu aria-hidden=\"true\" className=\"size-6\" />\n </button>\n <nav\n aria-label={mobileNavigation.navigationLabel}\n className=\"fixed top-[4.5rem] right-[1.25rem] m-0 w-72 rounded-card border border-border-subtle bg-surface-raised p-3 shadow-float [@supports(position-anchor:--navbar-mobile-menu-trigger)]:absolute [@supports(position-anchor:--navbar-mobile-menu-trigger)]:top-[calc(anchor(bottom)+0.5rem)] [@supports(position-anchor:--navbar-mobile-menu-trigger)]:right-auto [@supports(position-anchor:--navbar-mobile-menu-trigger)]:left-[anchor(right)] [@supports(position-anchor:--navbar-mobile-menu-trigger)]:-translate-x-full\"\n id={mobileNavigationId}\n popover=\"auto\"\n style={{positionAnchor: mobileNavigationAnchorName}}\n >\n {renderLinks(mobileLinkClassName)}\n {mobileNavigation.actions ? (\n <div className=\"mt-2 space-y-3 border-t border-border-subtle pt-3\">\n {mobileNavigation.actions}\n </div>\n ) : null}\n </nav>\n </div>\n ) : null}\n </div>\n </header>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","useId","jsx","jsxs"]}
|