@apliteni/apliteni-ui 0.137.0 → 0.138.0
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/package.json +1 -1
- package/react/README.md +25 -0
- package/react/dist/index.d.ts +67 -2
- package/react/dist/index.js +180 -39
- package/src/components/topbar.js +3 -3
- package/src/styles/topbar.css +24 -9
package/package.json
CHANGED
package/react/README.md
CHANGED
|
@@ -232,6 +232,8 @@ finds its rows by `data-dd-item`, which is in the props you spread.
|
|
|
232
232
|
leave `open` out and the component keeps its own, starting from `defaultOpen`. `onSelect`
|
|
233
233
|
reports the item's `value` and the item. Pass `ariaLabel` to a `select` dropdown: a listbox
|
|
234
234
|
needs a name, and axe says so — the same reason every vanilla dropdown story passes one.
|
|
235
|
+
Pass `selectedValue` when the caller owns the selected row. Its tick stays on that value after
|
|
236
|
+
`onSelect` until the caller changes it.
|
|
235
237
|
|
|
236
238
|
**`search` puts a field over the rows**, the same one the factory draws, and Guidelines /
|
|
237
239
|
Component choice makes it a rule at ten options or any list fed by data:
|
|
@@ -976,6 +978,29 @@ instead of 32, with the same line drawn in the middle of it.
|
|
|
976
978
|
]} />
|
|
977
979
|
```
|
|
978
980
|
|
|
981
|
+
## TopBar
|
|
982
|
+
|
|
983
|
+
`TopBar` is the band: the brand first, then your slots after the spacer. Fill `view`, `version`,
|
|
984
|
+
`theme` and `account` with `ViewSwitch`, `VersionSwitcher`, `ThemeToggle` and `AccountMenu`, or
|
|
985
|
+
leave one out. Leave out `account` for the signed-out bar. The brand is the Apliteni mark and
|
|
986
|
+
`word`, or pass your own `brand`. Put it above `AppShell` or on its own.
|
|
987
|
+
|
|
988
|
+
```tsx
|
|
989
|
+
<TopBar
|
|
990
|
+
view={<ViewSwitch items={[{ id: 'deck', label: 'Deck' }, { id: 'text', label: 'Text' }]} active="deck" />}
|
|
991
|
+
version={<VersionSwitcher versions={versions} value={version} onChange={setVersion} />}
|
|
992
|
+
theme={<ThemeToggle />}
|
|
993
|
+
account={<AccountMenu name="Ada Lovelace" email="ada@apliteni.com" current="prefs" onSignOut={signOut} />} />
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
`ViewSwitch` is a group of links, so it takes `renderLink` like `NavTabs`. The current view is
|
|
997
|
+
filled with the same accent fill as a `Segmented` choice and has `aria-current="page"`.
|
|
998
|
+
`VersionSwitcher` takes `{ value, label, badge }` versions. The button shows only the chosen
|
|
999
|
+
name. Each row shows a name, a badge and the selected tick. `AccountMenu` shows the
|
|
1000
|
+
avatar mark, the reader's name and address, the rows in `items` and Sign out. Both menus are the
|
|
1001
|
+
kit's `Dropdown`, so they share its keyboard and placement. `current` marks one account page in
|
|
1002
|
+
accent ink and defaults to `prefs`.
|
|
1003
|
+
|
|
979
1004
|
## NavTabs and Breadcrumbs
|
|
980
1005
|
|
|
981
1006
|
`NavTabs` renders route links with the kit’s underline or pill presentation. Pass
|
package/react/dist/index.d.ts
CHANGED
|
@@ -560,6 +560,8 @@ type DropdownProps = {
|
|
|
560
560
|
label?: string;
|
|
561
561
|
/** What the trigger shows. Given one, the trigger is yours to update. */
|
|
562
562
|
value?: string;
|
|
563
|
+
/** When given, the caller owns the selected row, including after a pick. */
|
|
564
|
+
selectedValue?: string | number;
|
|
563
565
|
placeholder?: string;
|
|
564
566
|
/** Inferred from the items when it is left out, exactly as the factory infers it. */
|
|
565
567
|
variant?: 'select' | 'menu';
|
|
@@ -598,7 +600,7 @@ type DropdownProps = {
|
|
|
598
600
|
/** Draw the row yourself. `props` is everything the row needs; spread it. */
|
|
599
601
|
row?: (item: DropdownItem, props: DropdownRowProps) => ReactNode;
|
|
600
602
|
};
|
|
601
|
-
declare function Dropdown({ label, value, placeholder, variant, items, sections, header, footer, triggerContent, triggerClass, disabled, chevron, align, direction, scroll, search, ariaLabel, id, panelClass, 'aria-describedby': describedBy, 'aria-invalid': invalid, open: openProp, defaultOpen, onOpenChange, onSelect, row, }: DropdownProps): react.JSX.Element;
|
|
603
|
+
declare function Dropdown({ label, value, selectedValue, placeholder, variant, items, sections, header, footer, triggerContent, triggerClass, disabled, chevron, align, direction, scroll, search, ariaLabel, id, panelClass, 'aria-describedby': describedBy, 'aria-invalid': invalid, open: openProp, defaultOpen, onOpenChange, onSelect, row, }: DropdownProps): react.JSX.Element;
|
|
602
604
|
|
|
603
605
|
type BackLinkOwnProps = {
|
|
604
606
|
/** The address. No address, or a `javascript:` one, and nothing is rendered. */
|
|
@@ -1201,6 +1203,69 @@ declare const AccentPicker: react.ForwardRefExoticComponent<Omit<HTMLAttributes<
|
|
|
1201
1203
|
options?: readonly Accent[];
|
|
1202
1204
|
} & react.RefAttributes<HTMLDivElement>>;
|
|
1203
1205
|
|
|
1206
|
+
type TopBarProps = Omit<ComponentPropsWithoutRef<'header'>, 'children'> & {
|
|
1207
|
+
/** The lockup. Left out, the bar draws the Apliteni mark and `word`. */
|
|
1208
|
+
brand?: ReactNode;
|
|
1209
|
+
/** The product word beside the mark, when `brand` is left out. */
|
|
1210
|
+
word?: string;
|
|
1211
|
+
brandHref?: string;
|
|
1212
|
+
/** A `ViewSwitch`, or nothing. */
|
|
1213
|
+
view?: ReactNode;
|
|
1214
|
+
/** A `VersionSwitcher`, or nothing. */
|
|
1215
|
+
version?: ReactNode;
|
|
1216
|
+
/** A `ThemeToggle`, or nothing. */
|
|
1217
|
+
theme?: ReactNode;
|
|
1218
|
+
/** An `AccountMenu`. Left out, the bar is the signed-out bar. */
|
|
1219
|
+
account?: ReactNode;
|
|
1220
|
+
};
|
|
1221
|
+
/** The band: brand first, the controls after the spacer. Each control is a slot. */
|
|
1222
|
+
declare function TopBar({ brand, word, brandHref, view, version, theme, account, className, ...rest }: TopBarProps): react.JSX.Element;
|
|
1223
|
+
type ViewSwitchItem = {
|
|
1224
|
+
id: string;
|
|
1225
|
+
label: string;
|
|
1226
|
+
href?: string;
|
|
1227
|
+
target?: string;
|
|
1228
|
+
};
|
|
1229
|
+
type ViewSwitchProps = {
|
|
1230
|
+
items: readonly ViewSwitchItem[];
|
|
1231
|
+
active: string;
|
|
1232
|
+
/** Names the group. */
|
|
1233
|
+
label?: string;
|
|
1234
|
+
/** Spread linkProps onto the router link, including children. */
|
|
1235
|
+
renderLink?: (item: ViewSwitchItem, linkProps: ComponentPropsWithoutRef<'a'>) => ReactNode;
|
|
1236
|
+
};
|
|
1237
|
+
/** The Deck and Text switch: links between views of one page, the current one filled. */
|
|
1238
|
+
declare function ViewSwitch({ items, active, label, renderLink }: ViewSwitchProps): react.JSX.Element;
|
|
1239
|
+
type Version = {
|
|
1240
|
+
value: string;
|
|
1241
|
+
label: string;
|
|
1242
|
+
badge?: 'live' | 'archive';
|
|
1243
|
+
};
|
|
1244
|
+
type VersionSwitcherProps = {
|
|
1245
|
+
versions: readonly Version[];
|
|
1246
|
+
value: string;
|
|
1247
|
+
onChange?: (value: string) => void;
|
|
1248
|
+
/** Names the list and the button. */
|
|
1249
|
+
label?: string;
|
|
1250
|
+
defaultOpen?: boolean;
|
|
1251
|
+
};
|
|
1252
|
+
/** The version menu: the button shows the chosen name, the open list ticks it. */
|
|
1253
|
+
declare function VersionSwitcher({ versions, value, onChange, label, defaultOpen }: VersionSwitcherProps): react.JSX.Element;
|
|
1254
|
+
type AccountMenuProps = {
|
|
1255
|
+
name: string;
|
|
1256
|
+
email: string;
|
|
1257
|
+
/** The rows above Sign out. Left out, the kit's account pages. */
|
|
1258
|
+
items?: DropdownEntry[];
|
|
1259
|
+
/** The current account page. One menu row takes the accent ink. */
|
|
1260
|
+
current?: string;
|
|
1261
|
+
signOutHref?: string;
|
|
1262
|
+
onSignOut?: () => void;
|
|
1263
|
+
onSelect?: (value: string | number | undefined) => void;
|
|
1264
|
+
defaultOpen?: boolean;
|
|
1265
|
+
};
|
|
1266
|
+
/** The avatar and its menu. */
|
|
1267
|
+
declare function AccountMenu({ name, email, items, current, signOutHref, onSignOut, onSelect, defaultOpen, }: AccountMenuProps): react.JSX.Element;
|
|
1268
|
+
|
|
1204
1269
|
type NavTabBadge = string | number | {
|
|
1205
1270
|
text: string | number;
|
|
1206
1271
|
tone?: 'neutral' | 'accent' | 'live' | 'danger';
|
|
@@ -1248,4 +1313,4 @@ declare const Breadcrumbs: react.ForwardRefExoticComponent<Omit<Omit<react.Detai
|
|
|
1248
1313
|
declare const PAGE_SIZES: readonly number[];
|
|
1249
1314
|
declare const DEFAULT_PAGE_SIZE: number;
|
|
1250
1315
|
|
|
1251
|
-
export { type Accent, AccentPicker, type AccentPickerProps, type AddFilter, AppShell, type AppShellProps, type AppShellSection, Avatar, type AvatarProps, BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, BusyRegion, type BusyRegionProps, Button, type ButtonLinkProps, type ButtonProps, Callout, type CalloutProps, type CalloutVariant, Card, Chart, type ChartBridgeStep, type ChartBridgeTones, type ChartPeriod, type ChartProps, type ChartSeries, type ChartTone, CheckList, type CheckListProps, Checkbox, type CheckboxProps, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, Confirm, type ConfirmProps, DEFAULT_PAGE_SIZE, DataTable, type DataTableProps, DatePicker, type DatePickerMode, type DatePickerPreset, type DatePickerProps, type DatePickerRange, DeltaValue, type DeltaValueProps, Denied, type DeniedProps, Drawer, type DrawerProps, DrawerSection, type DrawerSectionProps, Dropdown, type DropdownAvatar, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, EmptyState, type EmptyStateProps, type EmptyStateVariant, Feedback, type FeedbackPayload, type FeedbackProps, type FeedbackResult, type FeedbackSection, Field, type FieldControlProps, type FieldProps, FileDrop, type FileDropFile, type FileDropProps, type FileDropStatus, FileField, type FileFieldProps, type Filter, FilterBar, type FilterBarProps, Footer, type FooterColumn, type FooterLink, type FooterProps, type FooterSocial, Icon, KeyValueList, type KeyValueListProps, type KeyValueRow, Modal, type ModalProps, type NativeButtonProps, type NavTabBadge, type NavTabItem, NavTabs, type NavTabsProps, NumericValue, type NumericValueProps, PAGE_SIZES, Pagination, type PaginationProps, Pill, type PillProps, RowIdentity, type RowIdentityProps, SearchField, type SearchFieldProps, type SegmentOption, Segmented, type SegmentedProps, SelectField, type SelectFieldProps, SidebarNav, type SidebarNavBadge, type SidebarNavItem, type SidebarNavLeaf, type SidebarNavProps, type SidebarNavSection, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, StatusDot, type StatusDotProps, Success, SuccessCheck, type SuccessCheckProps, type SuccessCountdown, SuccessPanel, type SuccessPanelProps, type SuccessProps, Switch, type SwitchProps, THEME_INIT_SCRIPT, type TabItem, type TableSort, Tabs, type TabsProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, ThemeToggle, type ThemeToggleProps, Timeline, type TimelineEvent, type TimelineEventKind, type TimelineProps, Toast, type ToastNotice, type ToastProps, Tooltip, type TooltipProps, sortTableRows, useToast };
|
|
1316
|
+
export { type Accent, AccentPicker, type AccentPickerProps, AccountMenu, type AccountMenuProps, type AddFilter, AppShell, type AppShellProps, type AppShellSection, Avatar, type AvatarProps, BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, type BreadcrumbItem, Breadcrumbs, type BreadcrumbsProps, BusyRegion, type BusyRegionProps, Button, type ButtonLinkProps, type ButtonProps, Callout, type CalloutProps, type CalloutVariant, Card, Chart, type ChartBridgeStep, type ChartBridgeTones, type ChartPeriod, type ChartProps, type ChartSeries, type ChartTone, CheckList, type CheckListProps, Checkbox, type CheckboxProps, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, Confirm, type ConfirmProps, DEFAULT_PAGE_SIZE, DataTable, type DataTableProps, DatePicker, type DatePickerMode, type DatePickerPreset, type DatePickerProps, type DatePickerRange, DeltaValue, type DeltaValueProps, Denied, type DeniedProps, Drawer, type DrawerProps, DrawerSection, type DrawerSectionProps, Dropdown, type DropdownAvatar, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, EmptyState, type EmptyStateProps, type EmptyStateVariant, Feedback, type FeedbackPayload, type FeedbackProps, type FeedbackResult, type FeedbackSection, Field, type FieldControlProps, type FieldProps, FileDrop, type FileDropFile, type FileDropProps, type FileDropStatus, FileField, type FileFieldProps, type Filter, FilterBar, type FilterBarProps, Footer, type FooterColumn, type FooterLink, type FooterProps, type FooterSocial, Icon, KeyValueList, type KeyValueListProps, type KeyValueRow, Modal, type ModalProps, type NativeButtonProps, type NavTabBadge, type NavTabItem, NavTabs, type NavTabsProps, NumericValue, type NumericValueProps, PAGE_SIZES, Pagination, type PaginationProps, Pill, type PillProps, RowIdentity, type RowIdentityProps, SearchField, type SearchFieldProps, type SegmentOption, Segmented, type SegmentedProps, SelectField, type SelectFieldProps, SidebarNav, type SidebarNavBadge, type SidebarNavItem, type SidebarNavLeaf, type SidebarNavProps, type SidebarNavSection, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, StatusDot, type StatusDotProps, Success, SuccessCheck, type SuccessCheckProps, type SuccessCountdown, SuccessPanel, type SuccessPanelProps, type SuccessProps, Switch, type SwitchProps, THEME_INIT_SCRIPT, type TabItem, type TableSort, Tabs, type TabsProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, ThemeToggle, type ThemeToggleProps, Timeline, type TimelineEvent, type TimelineEventKind, type TimelineProps, Toast, type ToastNotice, type ToastProps, Tooltip, type TooltipProps, TopBar, type TopBarProps, type Version, VersionSwitcher, type VersionSwitcherProps, ViewSwitch, type ViewSwitchItem, type ViewSwitchProps, sortTableRows, useToast };
|
package/react/dist/index.js
CHANGED
|
@@ -94,7 +94,7 @@ var cx = (...a) => a.filter(Boolean).join(" ");
|
|
|
94
94
|
var Button = forwardRef3(function Button2({
|
|
95
95
|
variant = "secondary",
|
|
96
96
|
size = "md",
|
|
97
|
-
icon:
|
|
97
|
+
icon: icon9,
|
|
98
98
|
leading,
|
|
99
99
|
iconRight,
|
|
100
100
|
iconOnly,
|
|
@@ -158,7 +158,7 @@ var Button = forwardRef3(function Button2({
|
|
|
158
158
|
className
|
|
159
159
|
);
|
|
160
160
|
const labelled = rest["aria-label"] != null || rest["aria-labelledby"] != null;
|
|
161
|
-
const fallback = typeof children === "string" && children.trim() ? children.trim() :
|
|
161
|
+
const fallback = typeof children === "string" && children.trim() ? children.trim() : icon9;
|
|
162
162
|
const named = iconOnly && !labelled && fallback ? { "aria-label": fallback, title: rest.title ?? fallback } : {};
|
|
163
163
|
const Root = href === void 0 ? "button" : "a";
|
|
164
164
|
return /* @__PURE__ */ jsxs3(
|
|
@@ -203,7 +203,7 @@ var Button = forwardRef3(function Button2({
|
|
|
203
203
|
if (!blockKey(event)) onKeyUp?.(event);
|
|
204
204
|
},
|
|
205
205
|
children: [
|
|
206
|
-
leading != null ? /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", style: { display: "inline-flex" }, children: leading }) :
|
|
206
|
+
leading != null ? /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", style: { display: "inline-flex" }, children: leading }) : icon9 && /* @__PURE__ */ jsx4(Icon, { name: icon9 }),
|
|
207
207
|
!iconOnly && renderedChildren != null && /* @__PURE__ */ jsx4("span", { className: "ui-btn__label-slot", children: /* @__PURE__ */ jsx4("span", { className: "ui-btn__label", ref: labelRef, children: renderedChildren }) }),
|
|
208
208
|
iconRight && /* @__PURE__ */ jsx4(Icon, { name: iconRight }),
|
|
209
209
|
busy && /* @__PURE__ */ jsxs3("span", { className: "ui-btn__dots", "aria-hidden": "true", children: [
|
|
@@ -284,14 +284,14 @@ var StatusDot = forwardRef5(function StatusDot2({
|
|
|
284
284
|
// src/primitives/Card.tsx
|
|
285
285
|
import { icon as kitIcon, safeUrl } from "@apliteni/apliteni-ui";
|
|
286
286
|
import { Fragment, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
287
|
-
function Card({ title, sub, level = 2, variant, pad: pad2, icon:
|
|
287
|
+
function Card({ title, sub, level = 2, variant, pad: pad2, icon: icon9, href, className, children }) {
|
|
288
288
|
const n = Number(level);
|
|
289
289
|
const Heading = href != null ? "div" : `h${[2, 3, 4, 5, 6].includes(n) ? n : 2}`;
|
|
290
290
|
const titled = title != null && title !== false && title !== "";
|
|
291
291
|
const classes = ["ui-card", variant && `ui-card--${variant}`, pad2 && `ui-card--pad-${pad2}`, href != null && "ui-card--interactive", className].filter(Boolean).join(" ");
|
|
292
292
|
const inner = /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
293
293
|
titled && /* @__PURE__ */ jsxs5(Heading, { className: "ui-card__title", children: [
|
|
294
|
-
|
|
294
|
+
icon9 && /* @__PURE__ */ jsx9("span", { className: "ui-card__icon", "aria-hidden": "true", dangerouslySetInnerHTML: { __html: kitIcon(icon9) } }),
|
|
295
295
|
title
|
|
296
296
|
] }),
|
|
297
297
|
sub != null && /* @__PURE__ */ jsx9("div", { className: "ui-card__sub", children: sub }),
|
|
@@ -303,9 +303,9 @@ function Card({ title, sub, level = 2, variant, pad: pad2, icon: icon8, href, cl
|
|
|
303
303
|
// src/primitives/Callout.tsx
|
|
304
304
|
import { calloutIcons, icon as kitIcon2 } from "@apliteni/apliteni-ui";
|
|
305
305
|
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
306
|
-
function Callout({ variant, icon:
|
|
306
|
+
function Callout({ variant, icon: icon9 = calloutIcons[variant ?? "neutral"], children, actions }) {
|
|
307
307
|
return /* @__PURE__ */ jsxs6("div", { className: `ui-callout${variant && variant !== "neutral" ? ` ui-callout--${variant}` : ""}`, role: variant === "danger" ? "alert" : void 0, children: [
|
|
308
|
-
/* @__PURE__ */ jsx10("span", { className: "ui-callout__icon", dangerouslySetInnerHTML: { __html: kitIcon2(
|
|
308
|
+
/* @__PURE__ */ jsx10("span", { className: "ui-callout__icon", dangerouslySetInnerHTML: { __html: kitIcon2(icon9) } }),
|
|
309
309
|
/* @__PURE__ */ jsxs6("div", { className: "ui-callout__body", children: [
|
|
310
310
|
children,
|
|
311
311
|
actions != null && /* @__PURE__ */ jsx10("div", { className: "ui-toolbar ui-callout__actions", children: actions })
|
|
@@ -1882,12 +1882,12 @@ function Denied({
|
|
|
1882
1882
|
title = "You don\u2019t have access",
|
|
1883
1883
|
sub,
|
|
1884
1884
|
need,
|
|
1885
|
-
icon:
|
|
1885
|
+
icon: icon9 = "lock",
|
|
1886
1886
|
className,
|
|
1887
1887
|
children
|
|
1888
1888
|
}) {
|
|
1889
1889
|
return /* @__PURE__ */ jsxs16("div", { className: cx4("ui-denied", className), children: [
|
|
1890
|
-
/* @__PURE__ */ jsx20("div", { className: "ui-denied__seal", children: /* @__PURE__ */ jsx20(Icon, { name:
|
|
1890
|
+
/* @__PURE__ */ jsx20("div", { className: "ui-denied__seal", children: /* @__PURE__ */ jsx20(Icon, { name: icon9 }) }),
|
|
1891
1891
|
/* @__PURE__ */ jsx20("div", { className: "ui-denied__title", children: title }),
|
|
1892
1892
|
sub && /* @__PURE__ */ jsx20("div", { className: "ui-denied__sub", children: sub }),
|
|
1893
1893
|
need && /* @__PURE__ */ jsxs16("div", { className: "ui-denied__need", children: [
|
|
@@ -2440,6 +2440,7 @@ var SEARCH_DEFAULTS = {
|
|
|
2440
2440
|
function Dropdown({
|
|
2441
2441
|
label,
|
|
2442
2442
|
value,
|
|
2443
|
+
selectedValue,
|
|
2443
2444
|
placeholder = "Select\u2026",
|
|
2444
2445
|
variant,
|
|
2445
2446
|
items,
|
|
@@ -2584,15 +2585,16 @@ function Dropdown({
|
|
|
2584
2585
|
const name = ariaLabel || (label ? String(label).replace(/:\s*$/, "") : "") || "Options";
|
|
2585
2586
|
const given = rows.find((it) => it.selected);
|
|
2586
2587
|
const givenKey = given ? keyOf(given) : null;
|
|
2587
|
-
const pickedKey = pick && pick.against === givenKey ? pick.key : null;
|
|
2588
|
+
const pickedKey = selectedValue === void 0 && pick && pick.against === givenKey ? pick.key : null;
|
|
2588
2589
|
useEffect8(() => {
|
|
2589
2590
|
if (pick && pick.against !== givenKey) setPick(null);
|
|
2590
2591
|
}, [givenKey, pick]);
|
|
2591
2592
|
const picked = pickedKey != null ? rows.find((it) => keyOf(it) === pickedKey) : void 0;
|
|
2592
|
-
const
|
|
2593
|
+
const controlled = selectedValue !== void 0 ? rows.find((it) => it.value === selectedValue) : void 0;
|
|
2594
|
+
const shown = value != null ? value : isSelect ? selectedValue !== void 0 ? controlled?.label : picked?.label ?? given?.label : null;
|
|
2593
2595
|
const marked2 = isSelect && rows.some((it) => it.avatar);
|
|
2594
|
-
const chosen = marked2 ? value != null ? rows.find((it) => it.label === value) : picked ?? given : void 0;
|
|
2595
|
-
const selectedOf = (it) => pickedKey != null ? it.disabled ? !!it.selected : keyOf(it) === pickedKey : !!it.selected;
|
|
2596
|
+
const chosen = marked2 ? value != null ? rows.find((it) => it.label === value) : selectedValue !== void 0 ? controlled : picked ?? given : void 0;
|
|
2597
|
+
const selectedOf = (it) => selectedValue !== void 0 ? it.value === selectedValue : pickedKey != null ? it.disabled ? !!it.selected : keyOf(it) === pickedKey : !!it.selected;
|
|
2596
2598
|
const hiddenBy = (it) => Boolean(sx) && !dropdownMatch(it.label, query);
|
|
2597
2599
|
const filtering = Boolean(sx) && dropdownFiltering(query);
|
|
2598
2600
|
const visible = rows.filter((it) => !hiddenBy(it));
|
|
@@ -2770,7 +2772,7 @@ function Dropdown({
|
|
|
2770
2772
|
e.preventDefault();
|
|
2771
2773
|
return;
|
|
2772
2774
|
}
|
|
2773
|
-
if (isSelect) setPick({ key: keyOf(item), against: givenKey });
|
|
2775
|
+
if (isSelect && selectedValue === void 0) setPick({ key: keyOf(item), against: givenKey });
|
|
2774
2776
|
onSelect?.(item.value, item);
|
|
2775
2777
|
setOpen(false);
|
|
2776
2778
|
trigger.current?.focus();
|
|
@@ -3595,11 +3597,11 @@ var cases = {
|
|
|
3595
3597
|
"not-found": { title: "We can't find that page", sub: "Check the address or return to the home page.", icon: "folder" },
|
|
3596
3598
|
"not-yet-built": { title: "This ships later", sub: "This screen is not available yet. Check back later.", icon: "clock" }
|
|
3597
3599
|
};
|
|
3598
|
-
function EmptyState({ variant = "first-run", title, sub, icon:
|
|
3600
|
+
function EmptyState({ variant = "first-run", title, sub, icon: icon9, art, actions }) {
|
|
3599
3601
|
const preset = cases[variant];
|
|
3600
3602
|
const heading = title ?? preset.title;
|
|
3601
3603
|
const guidance = sub ?? preset.sub;
|
|
3602
|
-
const glyph =
|
|
3604
|
+
const glyph = icon9 ?? preset.icon;
|
|
3603
3605
|
return /* @__PURE__ */ jsxs27("div", { className: "ui-empty", children: [
|
|
3604
3606
|
art ? typeof art === "string" ? /* @__PURE__ */ jsx32("div", { className: "ui-empty__art", dangerouslySetInnerHTML: { __html: /<svg/.test(art) ? art : illo(art) } }) : /* @__PURE__ */ jsx32("div", { className: "ui-empty__art", "aria-hidden": "true", children: art }) : glyph ? /* @__PURE__ */ jsx32("div", { className: "ui-empty__icon", dangerouslySetInnerHTML: { __html: kitIcon3(glyph) } }) : null,
|
|
3605
3607
|
heading && /* @__PURE__ */ jsx32("div", { className: "ui-empty__title", children: heading }),
|
|
@@ -4341,10 +4343,10 @@ function Footer({
|
|
|
4341
4343
|
brand !== false && /* @__PURE__ */ jsxs34("div", { className: "ui-footer__brand", children: [
|
|
4342
4344
|
lockup,
|
|
4343
4345
|
tagline && /* @__PURE__ */ jsx39("p", { className: "ui-footer__tagline", children: tagline }),
|
|
4344
|
-
social.length > 0 && /* @__PURE__ */ jsx39("div", { className: "ui-footer__socials", children: social.map(({ label, href: to, icon:
|
|
4345
|
-
const markup = SOCIAL_GLYPHS[
|
|
4346
|
-
const fill =
|
|
4347
|
-
const viewBox =
|
|
4346
|
+
social.length > 0 && /* @__PURE__ */ jsx39("div", { className: "ui-footer__socials", children: social.map(({ label, href: to, icon: icon9 = "github" }) => {
|
|
4347
|
+
const markup = SOCIAL_GLYPHS[icon9];
|
|
4348
|
+
const fill = icon9 === "mail" ? "none" : "currentColor";
|
|
4349
|
+
const viewBox = icon9 === "linkedin" ? "0 0 448 512" : "0 0 24 24";
|
|
4348
4350
|
return /* @__PURE__ */ jsx39("a", { className: "ui-footer__social", href: safeUrl2(to ?? "#"), "aria-label": label, children: /* @__PURE__ */ jsx39("svg", { viewBox, fill, "aria-hidden": "true", dangerouslySetInnerHTML: { __html: markup } }) }, label);
|
|
4349
4351
|
}) })
|
|
4350
4352
|
] }),
|
|
@@ -5201,10 +5203,145 @@ var AccentPicker = forwardRef10(function AccentPicker2({
|
|
|
5201
5203
|
);
|
|
5202
5204
|
});
|
|
5203
5205
|
|
|
5204
|
-
// src/
|
|
5205
|
-
import { Fragment as Fragment17
|
|
5206
|
-
import { safeUrl as safeUrl3,
|
|
5206
|
+
// src/TopBar.tsx
|
|
5207
|
+
import { Fragment as Fragment17 } from "react";
|
|
5208
|
+
import { prism as prism3, safeUrl as safeUrl3, icon as icon7, ACCOUNT_NAV } from "@apliteni/apliteni-ui";
|
|
5207
5209
|
import { Fragment as Fragment18, jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
5210
|
+
function TopBar({
|
|
5211
|
+
brand,
|
|
5212
|
+
word = "Strategy",
|
|
5213
|
+
brandHref = "/",
|
|
5214
|
+
view,
|
|
5215
|
+
version,
|
|
5216
|
+
theme,
|
|
5217
|
+
account,
|
|
5218
|
+
className,
|
|
5219
|
+
...rest
|
|
5220
|
+
}) {
|
|
5221
|
+
return /* @__PURE__ */ jsx43("header", { ...rest, className: ["topbar", className].filter(Boolean).join(" "), children: /* @__PURE__ */ jsxs37("div", { className: "topbar__in", children: [
|
|
5222
|
+
brand ?? /* @__PURE__ */ jsxs37("a", { className: "brand", href: safeUrl3(brandHref), "aria-label": `Apliteni ${word}`, children: [
|
|
5223
|
+
/* @__PURE__ */ jsx43("span", { "aria-hidden": "true", dangerouslySetInnerHTML: { __html: prism3("tb-mark", 22) } }),
|
|
5224
|
+
/* @__PURE__ */ jsx43("span", { children: word })
|
|
5225
|
+
] }),
|
|
5226
|
+
view,
|
|
5227
|
+
/* @__PURE__ */ jsx43("span", { className: "spacer" }),
|
|
5228
|
+
version,
|
|
5229
|
+
theme,
|
|
5230
|
+
account
|
|
5231
|
+
] }) });
|
|
5232
|
+
}
|
|
5233
|
+
function ViewSwitch({ items, active, label = "View", renderLink }) {
|
|
5234
|
+
return /* @__PURE__ */ jsx43("div", { className: "dtsw on", role: "group", "aria-label": label, children: items.map((item) => {
|
|
5235
|
+
const current = item.id === active;
|
|
5236
|
+
const linkProps = {
|
|
5237
|
+
className: current ? "cur" : void 0,
|
|
5238
|
+
href: safeUrl3(item.href || `#${item.id}`),
|
|
5239
|
+
target: item.target,
|
|
5240
|
+
"aria-current": current ? "page" : void 0,
|
|
5241
|
+
children: item.label
|
|
5242
|
+
};
|
|
5243
|
+
return /* @__PURE__ */ jsx43(Fragment17, { children: renderLink ? renderLink(item, linkProps) : /* @__PURE__ */ jsx43("a", { ...linkProps }) }, item.id);
|
|
5244
|
+
}) });
|
|
5245
|
+
}
|
|
5246
|
+
var BADGE = { live: "Live", archive: "Archive" };
|
|
5247
|
+
function VersionSwitcher({ versions, value, onChange, label = "Version", defaultOpen }) {
|
|
5248
|
+
const current = versions.find((v) => v.value === value);
|
|
5249
|
+
return /* @__PURE__ */ jsx43("div", { className: "vsw", children: /* @__PURE__ */ jsx43(
|
|
5250
|
+
Dropdown,
|
|
5251
|
+
{
|
|
5252
|
+
variant: "select",
|
|
5253
|
+
align: "start",
|
|
5254
|
+
triggerClass: "vsw__btn",
|
|
5255
|
+
panelClass: "vsw__menu",
|
|
5256
|
+
selectedValue: value,
|
|
5257
|
+
chevron: false,
|
|
5258
|
+
defaultOpen,
|
|
5259
|
+
ariaLabel: `${label} \u2014 ${current?.label ?? ""}`,
|
|
5260
|
+
triggerContent: /* @__PURE__ */ jsxs37(Fragment18, { children: [
|
|
5261
|
+
/* @__PURE__ */ jsx43("span", { className: "cur", children: current?.label }),
|
|
5262
|
+
/* @__PURE__ */ jsx43("span", { className: "car", "aria-hidden": "true" })
|
|
5263
|
+
] }),
|
|
5264
|
+
items: versions.map((v) => ({
|
|
5265
|
+
label: v.label,
|
|
5266
|
+
value: v.value,
|
|
5267
|
+
badge: BADGE[v.badge ?? "archive"],
|
|
5268
|
+
selected: v.value === value
|
|
5269
|
+
})),
|
|
5270
|
+
row: (item, props) => /* @__PURE__ */ jsxs37("div", { ...props, className: `${props.className} vopt`, children: [
|
|
5271
|
+
/* @__PURE__ */ jsx43("span", { className: "vname", children: item.label }),
|
|
5272
|
+
/* @__PURE__ */ jsx43("span", { className: `vbadge ${item.badge === "Live" ? "live" : "arch"}`, children: String(item.badge) }),
|
|
5273
|
+
/* @__PURE__ */ jsx43("span", { className: "vtick", "aria-hidden": "true", dangerouslySetInnerHTML: { __html: icon7("check") } })
|
|
5274
|
+
] }),
|
|
5275
|
+
onSelect: (picked) => {
|
|
5276
|
+
if (picked != null) onChange?.(String(picked));
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
) });
|
|
5280
|
+
}
|
|
5281
|
+
var initialsOf = (name, email) => {
|
|
5282
|
+
const from = name.trim() || email.split("@")[0] || "";
|
|
5283
|
+
return (from.split(/[\s._-]+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join("") || "?").toUpperCase();
|
|
5284
|
+
};
|
|
5285
|
+
var ACCOUNT_ITEMS = ACCOUNT_NAV.map((item) => ({
|
|
5286
|
+
label: item.label,
|
|
5287
|
+
icon: item.icon,
|
|
5288
|
+
value: item.id,
|
|
5289
|
+
href: `#${item.id}`
|
|
5290
|
+
}));
|
|
5291
|
+
function AccountMenu({
|
|
5292
|
+
name,
|
|
5293
|
+
email,
|
|
5294
|
+
items = ACCOUNT_ITEMS,
|
|
5295
|
+
current = "prefs",
|
|
5296
|
+
signOutHref,
|
|
5297
|
+
onSignOut,
|
|
5298
|
+
onSelect,
|
|
5299
|
+
defaultOpen
|
|
5300
|
+
}) {
|
|
5301
|
+
const mark = initialsOf(name, email);
|
|
5302
|
+
return /* @__PURE__ */ jsx43("div", { className: "acct on", children: /* @__PURE__ */ jsx43(
|
|
5303
|
+
Dropdown,
|
|
5304
|
+
{
|
|
5305
|
+
variant: "menu",
|
|
5306
|
+
align: "end",
|
|
5307
|
+
chevron: false,
|
|
5308
|
+
triggerClass: "avatar",
|
|
5309
|
+
panelClass: "amenu",
|
|
5310
|
+
defaultOpen,
|
|
5311
|
+
ariaLabel: "Account",
|
|
5312
|
+
triggerContent: mark,
|
|
5313
|
+
header: /* @__PURE__ */ jsxs37("div", { className: "ahead", children: [
|
|
5314
|
+
/* @__PURE__ */ jsx43("span", { className: "avatar", children: mark }),
|
|
5315
|
+
/* @__PURE__ */ jsxs37("span", { className: "aw", children: [
|
|
5316
|
+
/* @__PURE__ */ jsx43("span", { className: "anm", children: name }),
|
|
5317
|
+
/* @__PURE__ */ jsx43("span", { className: "aem", title: email, children: email })
|
|
5318
|
+
] })
|
|
5319
|
+
] }),
|
|
5320
|
+
items: [...items, "---", { label: "Sign out", icon: "logout", value: "sign-out", href: signOutHref }],
|
|
5321
|
+
row: (item, props) => /* @__PURE__ */ jsxs37(
|
|
5322
|
+
"a",
|
|
5323
|
+
{
|
|
5324
|
+
...props,
|
|
5325
|
+
href: item.disabled ? void 0 : item.href ? safeUrl3(item.href) : item.value === "sign-out" && onSignOut ? void 0 : safeUrl3(item.value === "sign-out" ? "#logout" : `#${item.value}`),
|
|
5326
|
+
className: [props.className.replace(/\bui-dropdown__item\b/, "").trim(), !item.disabled && item.value === current && "cur", item.value === "sign-out" && "aout"].filter(Boolean).join(" "),
|
|
5327
|
+
children: [
|
|
5328
|
+
item.icon && /* @__PURE__ */ jsx43("span", { "aria-hidden": "true", dangerouslySetInnerHTML: { __html: icon7(item.icon) } }),
|
|
5329
|
+
item.label
|
|
5330
|
+
]
|
|
5331
|
+
}
|
|
5332
|
+
),
|
|
5333
|
+
onSelect: (value, item) => {
|
|
5334
|
+
if (item.value === "sign-out") onSignOut?.();
|
|
5335
|
+
else onSelect?.(value);
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
) });
|
|
5339
|
+
}
|
|
5340
|
+
|
|
5341
|
+
// src/NavTabs.tsx
|
|
5342
|
+
import { Fragment as Fragment19, forwardRef as forwardRef11, useEffect as useEffect18, useRef as useRef23, useImperativeHandle as useImperativeHandle2 } from "react";
|
|
5343
|
+
import { safeUrl as safeUrl4, observeNavFit, revealCurrentNav, revealFocusedNav } from "@apliteni/apliteni-ui";
|
|
5344
|
+
import { Fragment as Fragment20, jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
5208
5345
|
var NavTabs = forwardRef11(function NavTabs2({
|
|
5209
5346
|
items,
|
|
5210
5347
|
active,
|
|
@@ -5222,7 +5359,7 @@ var NavTabs = forwardRef11(function NavTabs2({
|
|
|
5222
5359
|
useEffect18(() => {
|
|
5223
5360
|
if (navRef.current) revealCurrentNav(navRef.current);
|
|
5224
5361
|
}, [active, signature]);
|
|
5225
|
-
return /* @__PURE__ */
|
|
5362
|
+
return /* @__PURE__ */ jsx44(
|
|
5226
5363
|
"nav",
|
|
5227
5364
|
{
|
|
5228
5365
|
...rest,
|
|
@@ -5235,20 +5372,20 @@ var NavTabs = forwardRef11(function NavTabs2({
|
|
|
5235
5372
|
},
|
|
5236
5373
|
children: items.map((item) => {
|
|
5237
5374
|
const badge = item.badge != null && typeof item.badge === "object" ? item.badge : { text: item.badge, tone: void 0 };
|
|
5238
|
-
const inner = /* @__PURE__ */
|
|
5239
|
-
/* @__PURE__ */
|
|
5240
|
-
badge.text != null && badge.text !== "" && /* @__PURE__ */
|
|
5375
|
+
const inner = /* @__PURE__ */ jsxs38(Fragment20, { children: [
|
|
5376
|
+
/* @__PURE__ */ jsx44("span", { className: "ui-nav__tab-label", children: item.label }),
|
|
5377
|
+
badge.text != null && badge.text !== "" && /* @__PURE__ */ jsx44("span", { className: `ui-nav__badge is-${badge.tone || "neutral"}`, children: badge.text })
|
|
5241
5378
|
] });
|
|
5242
|
-
if (item.disabled) return /* @__PURE__ */
|
|
5379
|
+
if (item.disabled) return /* @__PURE__ */ jsx44("span", { className: "ui-nav__tab is-disabled", "aria-disabled": "true", children: inner }, item.id);
|
|
5243
5380
|
const current = item.id === active;
|
|
5244
5381
|
const linkProps = {
|
|
5245
5382
|
className: ["ui-nav__tab", current && "is-active"].filter(Boolean).join(" "),
|
|
5246
|
-
href:
|
|
5383
|
+
href: safeUrl4(item.href || `#${item.id}`),
|
|
5247
5384
|
target: item.target,
|
|
5248
5385
|
"aria-current": current ? "page" : void 0,
|
|
5249
5386
|
children: inner
|
|
5250
5387
|
};
|
|
5251
|
-
return /* @__PURE__ */
|
|
5388
|
+
return /* @__PURE__ */ jsx44(Fragment19, { children: renderLink ? renderLink(item, linkProps) : /* @__PURE__ */ jsx44("a", { ...linkProps }) }, item.id);
|
|
5252
5389
|
})
|
|
5253
5390
|
}
|
|
5254
5391
|
);
|
|
@@ -5256,8 +5393,8 @@ var NavTabs = forwardRef11(function NavTabs2({
|
|
|
5256
5393
|
|
|
5257
5394
|
// src/Breadcrumbs.tsx
|
|
5258
5395
|
import { forwardRef as forwardRef12 } from "react";
|
|
5259
|
-
import { icon as
|
|
5260
|
-
import { Fragment as
|
|
5396
|
+
import { icon as icon8, safeUrl as safeUrl5 } from "@apliteni/apliteni-ui";
|
|
5397
|
+
import { Fragment as Fragment21, jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
5261
5398
|
var Breadcrumbs = forwardRef12(function Breadcrumbs2({
|
|
5262
5399
|
items,
|
|
5263
5400
|
renderLink,
|
|
@@ -5265,21 +5402,21 @@ var Breadcrumbs = forwardRef12(function Breadcrumbs2({
|
|
|
5265
5402
|
"aria-label": ariaLabel = "Breadcrumb",
|
|
5266
5403
|
...rest
|
|
5267
5404
|
}, ref) {
|
|
5268
|
-
return /* @__PURE__ */
|
|
5405
|
+
return /* @__PURE__ */ jsx45(
|
|
5269
5406
|
"nav",
|
|
5270
5407
|
{
|
|
5271
5408
|
...rest,
|
|
5272
5409
|
ref,
|
|
5273
5410
|
className: ["ui-nav", "ui-nav--crumbs", className].filter(Boolean).join(" "),
|
|
5274
5411
|
"aria-label": ariaLabel,
|
|
5275
|
-
children: /* @__PURE__ */
|
|
5412
|
+
children: /* @__PURE__ */ jsx45("ol", { className: "ui-nav__crumbs", children: items.map((item, index) => {
|
|
5276
5413
|
const current = index === items.length - 1;
|
|
5277
|
-
const inner = /* @__PURE__ */
|
|
5278
|
-
item.icon && /* @__PURE__ */
|
|
5279
|
-
/* @__PURE__ */
|
|
5414
|
+
const inner = /* @__PURE__ */ jsxs39(Fragment21, { children: [
|
|
5415
|
+
item.icon && /* @__PURE__ */ jsx45("span", { className: "ui-nav__ic", dangerouslySetInnerHTML: { __html: icon8(item.icon) } }),
|
|
5416
|
+
/* @__PURE__ */ jsx45("span", { className: "ui-nav__crumb-label", children: item.label })
|
|
5280
5417
|
] });
|
|
5281
|
-
const linkProps = !current && item.href ? { className: "ui-nav__crumb", href:
|
|
5282
|
-
return /* @__PURE__ */
|
|
5418
|
+
const linkProps = !current && item.href ? { className: "ui-nav__crumb", href: safeUrl5(item.href), target: item.target, children: inner } : null;
|
|
5419
|
+
return /* @__PURE__ */ jsx45("li", { className: "ui-nav__crumb-item", children: linkProps ? renderLink ? renderLink(item, linkProps) : /* @__PURE__ */ jsx45("a", { ...linkProps }) : /* @__PURE__ */ jsx45(
|
|
5283
5420
|
"span",
|
|
5284
5421
|
{
|
|
5285
5422
|
className: ["ui-nav__crumb", current && "is-current"].filter(Boolean).join(" "),
|
|
@@ -5297,6 +5434,7 @@ var PAGE_SIZES = KIT_PAGE_SIZES;
|
|
|
5297
5434
|
var DEFAULT_PAGE_SIZE3 = KIT_DEFAULT_PAGE_SIZE;
|
|
5298
5435
|
export {
|
|
5299
5436
|
AccentPicker,
|
|
5437
|
+
AccountMenu,
|
|
5300
5438
|
AppShell,
|
|
5301
5439
|
Avatar,
|
|
5302
5440
|
BackLink,
|
|
@@ -5356,6 +5494,9 @@ export {
|
|
|
5356
5494
|
Timeline,
|
|
5357
5495
|
Toast,
|
|
5358
5496
|
Tooltip,
|
|
5497
|
+
TopBar,
|
|
5498
|
+
VersionSwitcher,
|
|
5499
|
+
ViewSwitch,
|
|
5359
5500
|
sortTableRows,
|
|
5360
5501
|
useToast
|
|
5361
5502
|
};
|
package/src/components/topbar.js
CHANGED
|
@@ -38,11 +38,11 @@ export function versionSwitcher(versions = [], activeIdx = 0) {
|
|
|
38
38
|
const opts = versions.map((v, i) => {
|
|
39
39
|
const key = String(v.badge || 'archive').toLowerCase();
|
|
40
40
|
return `<div class="vopt" role="option" data-dd-item tabindex="-1" aria-selected="${i === activeIdx}" data-active="${i === activeIdx ? '1' : '0'}">` +
|
|
41
|
-
`<span
|
|
42
|
-
`<span class="vbadge ${key === 'live' ? 'live' : 'arch'}">${Object.hasOwn(VBADGE, key) ? VBADGE[key] : v.badge}</span></div>`;
|
|
41
|
+
`<span class="vname">${v.label}</span>` +
|
|
42
|
+
`<span class="vbadge ${key === 'live' ? 'live' : 'arch'}">${Object.hasOwn(VBADGE, key) ? VBADGE[key] : v.badge}</span><span class="vtick" aria-hidden="true">${icon('check')}</span></div>`;
|
|
43
43
|
}).join('');
|
|
44
44
|
return `<div class="vsw" data-dropdown><button type="button" class="vsw__btn" data-dropdown-trigger aria-haspopup="listbox" aria-expanded="false" aria-label="Version — ${esc(cur)}">` +
|
|
45
|
-
`<span class="
|
|
45
|
+
`<span class="cur">${cur}</span><span class="car"></span></button>` +
|
|
46
46
|
`<div class="vsw__menu" data-dropdown-panel role="listbox" aria-label="Version">${opts}</div></div>`;
|
|
47
47
|
}
|
|
48
48
|
|
package/src/styles/topbar.css
CHANGED
|
@@ -69,7 +69,11 @@
|
|
|
69
69
|
transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
|
|
70
70
|
}
|
|
71
71
|
.dtsw a:hover { color: var(--strong); }
|
|
72
|
-
.dtsw a.cur { color: var(--
|
|
72
|
+
.dtsw a.cur { color: var(--accent-contrast); background: var(--accent); }
|
|
73
|
+
:where(:root[data-theme="dark"]) .dtsw a.cur { color: var(--signal-contrast); }
|
|
74
|
+
@media (forced-colors: active) {
|
|
75
|
+
.dtsw a.cur { forced-color-adjust: none; background: Highlight; color: HighlightText; --ring: var(--ring-width) solid CanvasText; }
|
|
76
|
+
}
|
|
73
77
|
.dtsw a:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); }
|
|
74
78
|
|
|
75
79
|
/* Theme toggle — a single icon-only switch (no label). */
|
|
@@ -96,6 +100,7 @@
|
|
|
96
100
|
|
|
97
101
|
/* Version switcher */
|
|
98
102
|
.vsw { position: relative; }
|
|
103
|
+
.vsw > .ui-dropdown { max-width: 100%; min-width: 0; }
|
|
99
104
|
.vsw__btn {
|
|
100
105
|
display: inline-flex;
|
|
101
106
|
align-items: center;
|
|
@@ -117,16 +122,16 @@
|
|
|
117
122
|
what the kit's rows already chose. why: docs/foundations.md#the-focus-ring */
|
|
118
123
|
.vsw__btn:hover:not(:focus-visible) { border-color: var(--accent); }
|
|
119
124
|
.vsw__btn:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); }
|
|
120
|
-
.vsw__btn .lbl { color: var(--text); }
|
|
121
125
|
.vsw__btn .cur { color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
122
126
|
.vsw__btn .car {
|
|
123
127
|
width: 8px; height: 8px;
|
|
124
128
|
border-right: 1.6px solid var(--muted);
|
|
125
129
|
border-bottom: 1.6px solid var(--muted);
|
|
126
|
-
transform:
|
|
130
|
+
transform: translateY(-2px) rotate(45deg);
|
|
127
131
|
transition: transform var(--dur-fast) var(--ease);
|
|
128
132
|
}
|
|
129
|
-
.vsw.open .vsw__btn .car
|
|
133
|
+
.vsw.open .vsw__btn .car,
|
|
134
|
+
.vsw .ui-dropdown.open .vsw__btn .car { transform: translateY(2px) rotate(-135deg); }
|
|
130
135
|
.vsw__menu {
|
|
131
136
|
position: absolute;
|
|
132
137
|
top: calc(100% + 9px);
|
|
@@ -214,8 +219,12 @@
|
|
|
214
219
|
the arrow keys, and this is one. It takes the ring on its own 10px radius, the
|
|
215
220
|
same way `.amenu a` above does. #482 */
|
|
216
221
|
.vopt:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); }
|
|
222
|
+
/* The selected version carries the kit's menu tick, as `.ui-dropdown__tick` does for
|
|
223
|
+
every other menu; the badge keeps its own place beside it. */
|
|
224
|
+
.vopt .vtick { margin-left: 8px; flex: none; display: none; color: var(--accent); margin-top: 1px; }
|
|
225
|
+
.vopt .vtick svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2.4; }
|
|
226
|
+
.vopt[aria-selected="true"] .vtick { display: inline-flex; }
|
|
217
227
|
.vopt .vname { font-family: var(--font-sans); font-size: calc(var(--text-sm) - 0.5px); color: var(--strong); font-weight: 600; letter-spacing: 0.01em; }
|
|
218
|
-
.vopt .vmeta { font-size: var(--text-xs); color: var(--text); margin-top: 2px; }
|
|
219
228
|
.vopt .vbadge {
|
|
220
229
|
/* rank: chip */
|
|
221
230
|
font-size: var(--text-xs);
|
|
@@ -231,10 +240,8 @@
|
|
|
231
240
|
the same neutral chip fill rather than the card surface — which, inside a panel that
|
|
232
241
|
is itself lighter than a card, was darker than the ground it sat on. #453 */
|
|
233
242
|
.vbadge.arch { /* muted-ink: state — archived version */ color: var(--muted); background: var(--chip-neutral-fill); /* ring-gap: inherit — translucent wash retains the opaque containing gap. */ }
|
|
234
|
-
/*
|
|
235
|
-
Anchor the menu to its right edge so a closed panel cannot widen the page. */
|
|
243
|
+
/* Anchor the menu to its right edge so a closed panel cannot widen the page. */
|
|
236
244
|
@media (max-width: 720px) {
|
|
237
|
-
.vsw__btn .lbl { display: none; }
|
|
238
245
|
.vsw__menu { left: auto; right: 0; }
|
|
239
246
|
}
|
|
240
247
|
|
|
@@ -273,7 +280,7 @@
|
|
|
273
280
|
end inset. A long label gives way to an ellipsis, and 8px always stays between the
|
|
274
281
|
two controls. */
|
|
275
282
|
.topbar__in > .vsw { grid-area: 2 / 2 / 3 / -1; justify-self: end; min-width: 0; max-width: calc(100% - var(--space-2)); margin-left: var(--space-2); }
|
|
276
|
-
.vsw__btn { max-width: 100%; }
|
|
283
|
+
.vsw__btn { max-width: 100%; min-width: 0; }
|
|
277
284
|
.vsw__btn .cur { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
278
285
|
.vsw__btn .car { flex: none; }
|
|
279
286
|
/* Two 44px rows, an 8px gap, the 4px and 3px insets and the bottom border. */
|
|
@@ -304,6 +311,8 @@
|
|
|
304
311
|
accent band is the second band #578 round r34 took off the focus rules, and a
|
|
305
312
|
pointer resting on a focused control would put it back. One indicator, which is
|
|
306
313
|
what the kit's rows already chose. why: docs/foundations.md#the-focus-ring */
|
|
314
|
+
/* The React menu puts the dropdown trigger's pill padding and flex row on the avatar. */
|
|
315
|
+
.acct .avatar { display: grid; padding: 0; }
|
|
307
316
|
.acct .avatar:hover:not(:focus-visible) { border-color: var(--accent); }
|
|
308
317
|
.avatar:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); }
|
|
309
318
|
/* The account button holding an Avatar: the part paints the circle in the reader's hue and
|
|
@@ -376,6 +385,8 @@
|
|
|
376
385
|
border-radius: 14px 14px 0 0;
|
|
377
386
|
display: flex; align-items: center; gap: 11px;
|
|
378
387
|
}
|
|
388
|
+
.amenu .ui-dropdown__sep { margin: 5px 0; }
|
|
389
|
+
.amenu .ahead .avatar { cursor: default; }
|
|
379
390
|
.amenu .ahead .aw { min-width: 0; display: flex; flex-direction: column; gap: 1px; line-height: 1.35; }
|
|
380
391
|
.amenu .ahead .anm { color: var(--strong); font-size: var(--text-sm); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
381
392
|
.amenu .ahead .aem { color: var(--text); font-size: calc(var(--text-xs) + 0.5px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
@@ -388,6 +399,10 @@
|
|
|
388
399
|
.amenu a:hover { outline: 1px solid var(--control-edge); outline-offset: -1px; background: var(--surface); /* code-bg: inherit — control paint; the containing surface is the ground, for a chip and for a band alike. */ }
|
|
389
400
|
.amenu a:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); border-radius: var(--radius-xs); }
|
|
390
401
|
.amenu a.cur { color: var(--accent); }
|
|
402
|
+
/* A custom account row keeps the Dropdown's disabled state without its row shape. */
|
|
403
|
+
.amenu a.is-disabled { /* muted-ink: state — unavailable account page */ color: var(--disabled-ink); cursor: not-allowed; pointer-events: none; }
|
|
404
|
+
/* The SVG takes the row's height; its React wrapper adds no line box. */
|
|
405
|
+
.amenu a > span[aria-hidden="true"] { display: contents; }
|
|
391
406
|
.amenu a svg { width: 19px; height: 19px; flex: none; stroke: currentColor; fill: none; stroke-width: 2; opacity: 0.85; }
|
|
392
407
|
.amenu .asep { height: 1px; background: var(--border); margin: 5px 0; }
|
|
393
408
|
.amenu a.aout { color: var(--text); }
|