@misoto22/folio 0.17.1 → 0.18.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/dist/agent/Accordion.md +1 -1
- package/dist/agent/Actions.md +1 -1
- package/dist/agent/Alert.md +1 -1
- package/dist/agent/AppShell.md +1 -1
- package/dist/agent/ArchitectureFigure.md +1 -1
- package/dist/agent/AreaChart.md +1 -1
- package/dist/agent/Article.md +1 -1
- package/dist/agent/AspectRatio.md +1 -1
- package/dist/agent/Avatar.md +1 -1
- package/dist/agent/Badge.md +1 -1
- package/dist/agent/BarChart.md +1 -1
- package/dist/agent/BarList.md +1 -1
- package/dist/agent/BigNumber.md +1 -1
- package/dist/agent/BoxPlot.md +1 -1
- package/dist/agent/Breadcrumb.md +1 -1
- package/dist/agent/BulletChart.md +1 -1
- package/dist/agent/Button.md +1 -1
- package/dist/agent/Calendar.md +1 -1
- package/dist/agent/CalendarHeatmap.md +1 -1
- package/dist/agent/Card.md +1 -1
- package/dist/agent/Checkbox.md +1 -1
- package/dist/agent/Code.md +1 -1
- package/dist/agent/CodeBlock.md +1 -1
- package/dist/agent/Collapsible.md +1 -1
- package/dist/agent/Collection.md +1 -1
- package/dist/agent/ColorPicker.md +1 -1
- package/dist/agent/Combobox.md +1 -1
- package/dist/agent/Command.md +2 -1
- package/dist/agent/ComposedChart.md +1 -1
- package/dist/agent/Contact.md +1 -1
- package/dist/agent/Content.md +1 -1
- package/dist/agent/ContextMenu.md +1 -1
- package/dist/agent/Conversation.md +1 -1
- package/dist/agent/DataflowFigure.md +1 -1
- package/dist/agent/DatePicker.md +1 -1
- package/dist/agent/DescriptionList.md +1 -1
- package/dist/agent/Diagram.md +1 -1
- package/dist/agent/DiagramCanvas.md +1 -1
- package/dist/agent/DiagramExportMenu.md +1 -1
- package/dist/agent/DiagramInspector.md +1 -1
- package/dist/agent/DiagramLegend.md +1 -1
- package/dist/agent/DiagramMinimap.md +1 -1
- package/dist/agent/DiagramToolbar.md +1 -1
- package/dist/agent/Dialog.md +1 -1
- package/dist/agent/DropdownMenu.md +1 -1
- package/dist/agent/EmptyState.md +1 -1
- package/dist/agent/ErrorState.md +1 -1
- package/dist/agent/Evidence.md +1 -1
- package/dist/agent/Facet.md +1 -1
- package/dist/agent/Field.md +1 -1
- package/dist/agent/FigureBand.md +1 -1
- package/dist/agent/FloatingIconButton.md +1 -1
- package/dist/agent/FunnelChart.md +1 -1
- package/dist/agent/Heading.md +1 -1
- package/dist/agent/Heatmap.md +1 -1
- package/dist/agent/Histogram.md +1 -1
- package/dist/agent/Input.md +1 -1
- package/dist/agent/Kbd.md +1 -1
- package/dist/agent/LifecycleFigure.md +1 -1
- package/dist/agent/LineChart.md +1 -1
- package/dist/agent/LinkArrow.md +1 -1
- package/dist/agent/Markdown.md +1 -1
- package/dist/agent/Media.md +1 -1
- package/dist/agent/Metric.md +1 -1
- package/dist/agent/Metrics.md +1 -1
- package/dist/agent/Music.md +1 -1
- package/dist/agent/NativeSelect.md +1 -1
- package/dist/agent/NavItem.md +1 -1
- package/dist/agent/NumberField.md +1 -1
- package/dist/agent/PageHeader.md +1 -1
- package/dist/agent/Pagination.md +1 -1
- package/dist/agent/PieChart.md +1 -1
- package/dist/agent/Popover.md +1 -1
- package/dist/agent/Portfolio.md +1 -1
- package/dist/agent/PortfolioIndex.md +1 -1
- package/dist/agent/Progress.md +1 -1
- package/dist/agent/RadarChart.md +1 -1
- package/dist/agent/RadialChart.md +1 -1
- package/dist/agent/RadioGroup.md +1 -1
- package/dist/agent/Reading.md +10 -1
- package/dist/agent/Recovery.md +3 -3
- package/dist/agent/SankeyChart.md +1 -1
- package/dist/agent/ScatterChart.md +1 -1
- package/dist/agent/ScrollArea.md +1 -1
- package/dist/agent/SearchPalette.md +1 -1
- package/dist/agent/SearchableMenu.md +1 -1
- package/dist/agent/Select.md +1 -1
- package/dist/agent/Separator.md +1 -1
- package/dist/agent/SequenceFigure.md +1 -1
- package/dist/agent/Sheet.md +1 -1
- package/dist/agent/Sidebar.md +1 -1
- package/dist/agent/SiteNavigation.md +1 -1
- package/dist/agent/SiteShell.md +1 -1
- package/dist/agent/Skeleton.md +1 -1
- package/dist/agent/Slider.md +1 -1
- package/dist/agent/Sparkline.md +1 -1
- package/dist/agent/Spinner.md +1 -1
- package/dist/agent/StatusDot.md +1 -1
- package/dist/agent/StatusPill.md +1 -1
- package/dist/agent/Steps.md +1 -1
- package/dist/agent/Switch.md +1 -1
- package/dist/agent/Table.md +1 -1
- package/dist/agent/Tabs.md +1 -1
- package/dist/agent/Tag.md +1 -1
- package/dist/agent/Text.md +1 -1
- package/dist/agent/Textarea.md +1 -1
- package/dist/agent/Timeline.md +6 -2
- package/dist/agent/Timestamp.md +1 -1
- package/dist/agent/Toast.md +1 -1
- package/dist/agent/ToggleGroup.md +1 -1
- package/dist/agent/Toolbar.md +1 -1
- package/dist/agent/Tooltip.md +1 -1
- package/dist/agent/TreemapChart.md +1 -1
- package/dist/agent/WaterfallChart.md +1 -1
- package/dist/agent/Workbench.md +1 -1
- package/dist/agent/WorkflowFigure.md +1 -1
- package/dist/agent/catalog.json +10 -1
- package/dist/agent/index.md +2 -1
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Button/Button.js.map +1 -1
- package/dist/components/Command/Command.d.ts +3 -1
- package/dist/components/Command/Command.js +3 -2
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/keyframes.css +22 -0
- package/dist/styles.css +1 -1
- package/dist/themes.css +11 -0
- package/dist/tokens.css +14 -0
- package/dist/tokens.d.ts +4 -0
- package/dist/tokens.js +21 -0
- package/dist/tokens.json +21 -0
- package/dist/website/Media/Media.js +2 -2
- package/dist/website/Media/Media.js.map +1 -1
- package/dist/website/Reading/Reading.d.ts +7 -1
- package/dist/website/Reading/Reading.js +4 -0
- package/dist/website/Reading/Reading.js.map +1 -1
- package/dist/website/Recovery/Recovery.d.ts +10 -2
- package/dist/website/Recovery/Recovery.js +36 -2
- package/dist/website/Recovery/Recovery.js.map +1 -1
- package/dist/website/SearchPalette/SearchPalette.js +2 -0
- package/dist/website/SearchPalette/SearchPalette.js.map +1 -1
- package/dist/website/Timeline/Timeline.d.ts +11 -2
- package/dist/website/Timeline/Timeline.js +7 -1
- package/dist/website/Timeline/Timeline.js.map +1 -1
- package/dist/website/Workbench/theme.d.ts +2 -1
- package/dist/website/Workbench/theme.js +2 -1
- package/dist/website/Workbench/theme.js.map +1 -1
- package/dist/website/index.d.ts +2 -2
- package/dist/website-media.css +10 -4
- package/dist/website-reading.css +15 -4
- package/dist/website-recovery.css +8 -0
- package/dist/website-search.css +28 -14
- package/dist/website-timeline.css +6 -0
- package/package.json +1 -1
- package/skills/folio-design/rules/tokens.md +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/website/SearchPalette/SearchPalette.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, type KeyboardEvent, type ReactNode, type RefObject } from 'react'\nimport { RiArrowLeftLine, RiCloseLine } from '@remixicon/react'\nimport { Badge } from '../../components/Badge/Badge'\nimport { Button } from '../../components/Button/Button'\nimport { CommandDialog, CommandEmpty, CommandFooter, CommandGroup, CommandHint, CommandInput, CommandItem, CommandList } from '../../components/Command/Command'\nimport type { DialogContentProps } from '../../components/Dialog/Dialog'\nimport { Input } from '../../components/Input/Input'\n\nexport interface SearchPaletteItem {\n /** Stable identity, independent of a translated title. */\n id: string\n title: ReactNode\n description?: ReactNode\n icon?: ReactNode\n meta?: ReactNode\n onSelect: () => void\n}\n\nexport interface SearchPaletteGroup {\n id: string\n label: string\n items: SearchPaletteItem[]\n}\n\nexport interface SearchPaletteProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n label: string\n inputLabel: string\n placeholder: string\n query: string\n onQueryChange: (query: string) => void\n /** Already filtered results; search and data access belong to the consumer. */\n groups: SearchPaletteGroup[]\n emptyLabel: ReactNode\n labels: { close: string; navigate: string; select: string; back: string }\n /** Optional answer or detail view, with Escape returning to the results. */\n detail?: { label: string; content: ReactNode; onBack: () => void; onSubmit: () => void; submitDisabled?: boolean }\n onContentLinkClick?: () => void\n onCloseAutoFocus?: DialogContentProps['onCloseAutoFocus']\n}\n\n/** Search, actions and an optional result detail inside one accessible modal. */\nexport function SearchPalette({\n open, onOpenChange, label, inputLabel, placeholder, query, onQueryChange,\n groups, emptyLabel, labels, detail, onContentLinkClick, onCloseAutoFocus,\n}: SearchPaletteProps) {\n const input = useRef<HTMLInputElement>(null)\n const previousFocus = useRef<HTMLElement | null>(null)\n const showingDetail = Boolean(detail)\n useEffect(() => {\n if (open) input.current?.focus()\n }, [open, showingDetail])\n const close = () => onOpenChange(false)\n const field = { input, inputLabel, placeholder, query, onQueryChange }\n\n return (\n <CommandDialog\n open={open} onOpenChange={onOpenChange} label={label} inputLabel={inputLabel} shouldFilter={false}\n onOpenAutoFocus={() => {\n previousFocus.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n }}\n // A palette opened by a shortcut has no trigger for the dialog to return\n // focus to, so it goes back to whatever held it before opening.\n onCloseAutoFocus={(event) => {\n onCloseAutoFocus?.(event)\n if (!event.defaultPrevented) {\n event.preventDefault()\n previousFocus.current?.focus()\n }\n }}\n onEscapeKeyDown={(event) => {\n if (detail) { event.preventDefault(); detail.onBack() }\n }}\n >\n {detail\n ? <SearchDetail {...field} detail={detail} labels={labels} onClose={close} onContentLinkClick={onContentLinkClick} />\n : <SearchResults {...field} label={label} groups={groups} emptyLabel={emptyLabel} closeLabel={labels.close} onClose={close} />}\n <CommandFooter className=\"folio-search-palette__footer\">\n {!detail && <CommandHint keys={['↑', '↓']}>{labels.navigate}</CommandHint>}\n <CommandHint keys={['↵']}>{labels.select}</CommandHint>\n <CommandHint keys={['esc']}>{detail ? labels.back : labels.close}</CommandHint>\n </CommandFooter>\n </CommandDialog>\n )\n}\n\ninterface SearchFieldProps {\n input: RefObject<HTMLInputElement | null>\n inputLabel: string\n placeholder: string\n query: string\n onQueryChange: (query: string) => void\n onClose: () => void\n}\n\ninterface SearchResultsProps extends SearchFieldProps {\n label: string\n groups: SearchPaletteGroup[]\n emptyLabel: ReactNode\n closeLabel: string\n}\n\n/** The combobox over the host's groups, which the palette never filters again. */\nfunction SearchResults({ input, inputLabel, placeholder, query, onQueryChange, onClose, label, groups, emptyLabel, closeLabel }: SearchResultsProps) {\n return (\n <>\n <div className=\"folio-search-palette__search\">\n <CommandInput ref={input} aria-label={inputLabel} placeholder={placeholder} value={query} onValueChange={onQueryChange} autoComplete=\"off\" spellCheck={false} />\n <Button variant=\"ghost\" iconOnly aria-label={closeLabel} onClick={onClose} className=\"folio-search-palette__close\"><RiCloseLine size={18} aria-hidden /></Button>\n </div>\n <CommandList label={label}>\n <CommandEmpty>{emptyLabel}</CommandEmpty>\n {groups.map((group) => (\n <CommandGroup key={group.id} heading={<span className=\"folio-search-palette__heading\">{group.label}</span>}>\n {group.items.map((item) => (\n <CommandItem\n key={item.id} value={item.id} icon={item.icon} onSelect={item.onSelect} className=\"folio-search-palette__item\"\n meta={item.meta ? <span className=\"folio-search-palette__meta\">{item.meta}</span> : undefined}\n >\n <span className=\"folio-search-palette__result\">\n <span>{item.title}</span>\n {item.description && <span className=\"folio-search-palette__description\">{item.description}</span>}\n </span>\n </CommandItem>\n ))}\n </CommandGroup>\n ))}\n </CommandList>\n </>\n )\n}\n\ninterface SearchDetailProps extends SearchFieldProps {\n detail: NonNullable<SearchPaletteProps['detail']>\n labels: SearchPaletteProps['labels']\n onContentLinkClick?: () => void\n}\n\n/**\n * The keys the command list takes for itself: moving its highlight, and running\n * the highlighted row with Enter, which it does by cancelling the key. The\n * detail view has no list, and needs them back — Enter submits the question or\n * follows a link, and the others move the caret or scroll the answer — so they\n * stop here instead of reaching it.\n */\nconst LIST_KEYS = new Set(['Enter', 'Home', 'End', 'ArrowUp', 'ArrowDown'])\n\nfunction keepFromList(event: KeyboardEvent<HTMLElement>) {\n if (LIST_KEYS.has(event.key)) event.stopPropagation()\n}\n\n/** The answer view: a question field over content the host renders. */\nfunction SearchDetail({ input, inputLabel, placeholder, query, onQueryChange, onClose, detail, labels, onContentLinkClick }: SearchDetailProps) {\n return (\n <>\n <form className=\"folio-search-palette__input\" onKeyDown={keepFromList} onSubmit={(event) => {\n event.preventDefault()\n if (query.trim() && !detail.submitDisabled) detail.onSubmit()\n }}>\n <Button variant=\"ghost\" iconOnly aria-label={labels.back} onClick={detail.onBack}><RiArrowLeftLine size={18} aria-hidden /></Button>\n <Input ref={input} aria-label={inputLabel} placeholder={placeholder} value={query} onChange={(event) => onQueryChange(event.target.value)} autoComplete=\"off\" />\n <Badge>{detail.label}</Badge>\n <Button variant=\"ghost\" iconOnly aria-label={labels.close} onClick={onClose}><RiCloseLine size={18} aria-hidden /></Button>\n </form>\n <div className=\"folio-search-palette__detail\" aria-live=\"polite\" onKeyDown={keepFromList} onClick={(event) => {\n if ((event.target as HTMLElement).closest('a')) onContentLinkClick?.()\n }}>{detail.content}</div>\n </>\n )\n}\n\nexport interface SearchExcerptProps {\n segments: ReadonlyArray<{ text: string; highlighted: boolean }>\n}\n\n/** Render query highlights as text, never as consumer-supplied HTML. */\nexport function SearchExcerpt({ segments }: SearchExcerptProps) {\n return <>{segments.map((segment, index) => segment.highlighted\n ? <mark className=\"folio-search-palette__highlight\" key={index}>{segment.text}</mark>\n : segment.text)}</>\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/website/SearchPalette/SearchPalette.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, type KeyboardEvent, type ReactNode, type RefObject } from 'react'\nimport { RiArrowLeftLine, RiCloseLine } from '@remixicon/react'\nimport { Badge } from '../../components/Badge/Badge'\nimport { Button } from '../../components/Button/Button'\nimport { CommandDialog, CommandEmpty, CommandFooter, CommandGroup, CommandHint, CommandInput, CommandItem, CommandList } from '../../components/Command/Command'\nimport type { DialogContentProps } from '../../components/Dialog/Dialog'\nimport { Input } from '../../components/Input/Input'\n\nexport interface SearchPaletteItem {\n /** Stable identity, independent of a translated title. */\n id: string\n title: ReactNode\n description?: ReactNode\n icon?: ReactNode\n meta?: ReactNode\n onSelect: () => void\n}\n\nexport interface SearchPaletteGroup {\n id: string\n label: string\n items: SearchPaletteItem[]\n}\n\nexport interface SearchPaletteProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n label: string\n inputLabel: string\n placeholder: string\n query: string\n onQueryChange: (query: string) => void\n /** Already filtered results; search and data access belong to the consumer. */\n groups: SearchPaletteGroup[]\n emptyLabel: ReactNode\n labels: { close: string; navigate: string; select: string; back: string }\n /** Optional answer or detail view, with Escape returning to the results. */\n detail?: { label: string; content: ReactNode; onBack: () => void; onSubmit: () => void; submitDisabled?: boolean }\n onContentLinkClick?: () => void\n onCloseAutoFocus?: DialogContentProps['onCloseAutoFocus']\n}\n\nconst PANEL = 'folio-search-palette top-[max(4rem,15svh)] w-[min(94vw,40rem)] data-[state=open]:animate-[folio-palette-in_var(--duration-base)_var(--ease)] data-[state=closed]:animate-[folio-palette-out_var(--duration-fast)_var(--ease)]'\n\n/** Search, actions and an optional result detail inside one accessible modal. */\nexport function SearchPalette({\n open, onOpenChange, label, inputLabel, placeholder, query, onQueryChange,\n groups, emptyLabel, labels, detail, onContentLinkClick, onCloseAutoFocus,\n}: SearchPaletteProps) {\n const input = useRef<HTMLInputElement>(null)\n const previousFocus = useRef<HTMLElement | null>(null)\n const showingDetail = Boolean(detail)\n useEffect(() => {\n if (open) input.current?.focus()\n }, [open, showingDetail])\n const close = () => onOpenChange(false)\n const field = { input, inputLabel, placeholder, query, onQueryChange }\n\n return (\n <CommandDialog\n open={open} onOpenChange={onOpenChange} label={label} inputLabel={inputLabel} shouldFilter={false}\n // Placed on the optical centre rather than near the top edge: the panel's\n // resting height (field, ten rows, footer) puts its middle a little above\n // the viewport's. It settles in from a 6px lift and a hair of scale, and\n // leaves faster than it arrives, so closing never feels like waiting.\n className={PANEL}\n onOpenAutoFocus={() => {\n previousFocus.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n }}\n // A palette opened by a shortcut has no trigger for the dialog to return\n // focus to, so it goes back to whatever held it before opening.\n onCloseAutoFocus={(event) => {\n onCloseAutoFocus?.(event)\n if (!event.defaultPrevented) {\n event.preventDefault()\n previousFocus.current?.focus()\n }\n }}\n onEscapeKeyDown={(event) => {\n if (detail) { event.preventDefault(); detail.onBack() }\n }}\n >\n {detail\n ? <SearchDetail {...field} detail={detail} labels={labels} onClose={close} onContentLinkClick={onContentLinkClick} />\n : <SearchResults {...field} label={label} groups={groups} emptyLabel={emptyLabel} closeLabel={labels.close} onClose={close} />}\n <CommandFooter className=\"folio-search-palette__footer\">\n {!detail && <CommandHint keys={['↑', '↓']}>{labels.navigate}</CommandHint>}\n <CommandHint keys={['↵']}>{labels.select}</CommandHint>\n <CommandHint keys={['esc']}>{detail ? labels.back : labels.close}</CommandHint>\n </CommandFooter>\n </CommandDialog>\n )\n}\n\ninterface SearchFieldProps {\n input: RefObject<HTMLInputElement | null>\n inputLabel: string\n placeholder: string\n query: string\n onQueryChange: (query: string) => void\n onClose: () => void\n}\n\ninterface SearchResultsProps extends SearchFieldProps {\n label: string\n groups: SearchPaletteGroup[]\n emptyLabel: ReactNode\n closeLabel: string\n}\n\n/** The combobox over the host's groups, which the palette never filters again. */\nfunction SearchResults({ input, inputLabel, placeholder, query, onQueryChange, onClose, label, groups, emptyLabel, closeLabel }: SearchResultsProps) {\n return (\n <>\n <div className=\"folio-search-palette__search\">\n <CommandInput ref={input} aria-label={inputLabel} placeholder={placeholder} value={query} onValueChange={onQueryChange} autoComplete=\"off\" spellCheck={false} />\n <Button variant=\"ghost\" iconOnly aria-label={closeLabel} onClick={onClose} className=\"folio-search-palette__close\"><RiCloseLine size={18} aria-hidden /></Button>\n </div>\n <CommandList label={label}>\n <CommandEmpty>{emptyLabel}</CommandEmpty>\n {groups.map((group) => (\n <CommandGroup key={group.id} heading={<span className=\"folio-search-palette__heading\">{group.label}</span>}>\n {group.items.map((item) => (\n <CommandItem\n key={item.id} value={item.id} icon={item.icon} onSelect={item.onSelect} className=\"folio-search-palette__item\"\n meta={item.meta ? <span className=\"folio-search-palette__meta\">{item.meta}</span> : undefined}\n >\n <span className=\"folio-search-palette__result\">\n <span>{item.title}</span>\n {item.description && <span className=\"folio-search-palette__description\">{item.description}</span>}\n </span>\n </CommandItem>\n ))}\n </CommandGroup>\n ))}\n </CommandList>\n </>\n )\n}\n\ninterface SearchDetailProps extends SearchFieldProps {\n detail: NonNullable<SearchPaletteProps['detail']>\n labels: SearchPaletteProps['labels']\n onContentLinkClick?: () => void\n}\n\n/**\n * The keys the command list takes for itself: moving its highlight, and running\n * the highlighted row with Enter, which it does by cancelling the key. The\n * detail view has no list, and needs them back — Enter submits the question or\n * follows a link, and the others move the caret or scroll the answer — so they\n * stop here instead of reaching it.\n */\nconst LIST_KEYS = new Set(['Enter', 'Home', 'End', 'ArrowUp', 'ArrowDown'])\n\nfunction keepFromList(event: KeyboardEvent<HTMLElement>) {\n if (LIST_KEYS.has(event.key)) event.stopPropagation()\n}\n\n/** The answer view: a question field over content the host renders. */\nfunction SearchDetail({ input, inputLabel, placeholder, query, onQueryChange, onClose, detail, labels, onContentLinkClick }: SearchDetailProps) {\n return (\n <>\n <form className=\"folio-search-palette__input\" onKeyDown={keepFromList} onSubmit={(event) => {\n event.preventDefault()\n if (query.trim() && !detail.submitDisabled) detail.onSubmit()\n }}>\n <Button variant=\"ghost\" iconOnly aria-label={labels.back} onClick={detail.onBack}><RiArrowLeftLine size={18} aria-hidden /></Button>\n <Input ref={input} aria-label={inputLabel} placeholder={placeholder} value={query} onChange={(event) => onQueryChange(event.target.value)} autoComplete=\"off\" />\n <Badge>{detail.label}</Badge>\n <Button variant=\"ghost\" iconOnly aria-label={labels.close} onClick={onClose}><RiCloseLine size={18} aria-hidden /></Button>\n </form>\n <div className=\"folio-search-palette__detail\" aria-live=\"polite\" onKeyDown={keepFromList} onClick={(event) => {\n if ((event.target as HTMLElement).closest('a')) onContentLinkClick?.()\n }}>{detail.content}</div>\n </>\n )\n}\n\nexport interface SearchExcerptProps {\n segments: ReadonlyArray<{ text: string; highlighted: boolean }>\n}\n\n/** Render query highlights as text, never as consumer-supplied HTML. */\nexport function SearchExcerpt({ segments }: SearchExcerptProps) {\n return <>{segments.map((segment, index) => segment.highlighted\n ? <mark className=\"folio-search-palette__highlight\" key={index}>{segment.text}</mark>\n : segment.text)}</>\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,6 +9,15 @@ interface RecordSectionProps extends HTMLAttributes<HTMLElement> {
|
|
|
9
9
|
}
|
|
10
10
|
/** A named ledger section. The host supplies its chronology without reordering. */
|
|
11
11
|
declare function RecordSection({ title, count, headingId, children, className, ...rest }: RecordSectionProps): react.JSX.Element;
|
|
12
|
+
/**
|
|
13
|
+
* One entry in a record's tag row. A bare string is a text chip; an object can
|
|
14
|
+
* add a mark beside the label. The mark is decoration — `aria-hidden` — so the
|
|
15
|
+
* label is still the whole of what a screen reader hears.
|
|
16
|
+
*/
|
|
17
|
+
type CareerRecordTag = string | {
|
|
18
|
+
label: string;
|
|
19
|
+
icon?: ReactNode;
|
|
20
|
+
};
|
|
12
21
|
interface CareerRecordProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
13
22
|
title: string;
|
|
14
23
|
organization: ReactNode;
|
|
@@ -17,7 +26,7 @@ interface CareerRecordProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
|
17
26
|
location: string;
|
|
18
27
|
locationLabel: string;
|
|
19
28
|
description: string[];
|
|
20
|
-
tags:
|
|
29
|
+
tags: CareerRecordTag[];
|
|
21
30
|
tagsLabel: string;
|
|
22
31
|
mark?: ReactNode;
|
|
23
32
|
currentLabel?: string;
|
|
@@ -77,4 +86,4 @@ declare function Timeline({ className, ...props }: HTMLAttributes<HTMLDivElement
|
|
|
77
86
|
/** A record mount, isolated so motion can follow the shared data-motion axis. */
|
|
78
87
|
declare function TimelineItem({ className, ...props }: HTMLAttributes<HTMLDivElement>): react.JSX.Element;
|
|
79
88
|
|
|
80
|
-
export { CareerRecord, type CareerRecordProps, ProfileFigure, type ProfileFigureProps, ProfileInterests, type ProfileInterestsProps, ProfileNarrative, type ProfileNarrativeProps, ProfileSection, type ProfileSectionProps, type ProfileSkill, ProfileSkills, type ProfileSkillsProps, RecordSection, type RecordSectionProps, Timeline, TimelineItem };
|
|
89
|
+
export { CareerRecord, type CareerRecordProps, type CareerRecordTag, ProfileFigure, type ProfileFigureProps, ProfileInterests, type ProfileInterestsProps, ProfileNarrative, type ProfileNarrativeProps, ProfileSection, type ProfileSectionProps, type ProfileSkill, ProfileSkills, type ProfileSkillsProps, RecordSection, type RecordSectionProps, Timeline, TimelineItem };
|
|
@@ -29,7 +29,13 @@ function CareerRecord({ title, organization, period, periodLabel, location, loca
|
|
|
29
29
|
/* @__PURE__ */ jsx("div", { className: "mt-2", children: organization }),
|
|
30
30
|
description.length === 1 && /* @__PURE__ */ jsx(Text, { className: "mb-0 mt-5 max-w-(--measure-record)", children: description[0] }),
|
|
31
31
|
description.length > 1 && /* @__PURE__ */ jsx("ul", { className: "folio-career-record__description", children: description.map((point, index) => /* @__PURE__ */ jsx(Text, { as: "li", children: point }, index)) }),
|
|
32
|
-
tags.length > 0 && /* @__PURE__ */ jsx("ul", { "aria-label": tagsLabel, className: "folio-career-record__tags", children: tags.map((tag, index) =>
|
|
32
|
+
tags.length > 0 && /* @__PURE__ */ jsx("ul", { "aria-label": tagsLabel, className: "folio-career-record__tags", children: tags.map((tag, index) => {
|
|
33
|
+
const { label, icon } = typeof tag === "string" ? { label: tag, icon: void 0 } : tag;
|
|
34
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Tag, { className: "folio-career-record__tag", children: [
|
|
35
|
+
icon && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "folio-career-record__tag-mark", children: icon }),
|
|
36
|
+
label
|
|
37
|
+
] }) }, `${label}-${index}`);
|
|
38
|
+
}) })
|
|
33
39
|
] }),
|
|
34
40
|
mark && /* @__PURE__ */ jsx("div", { className: "folio-career-record__mark", children: mark })
|
|
35
41
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/website/Timeline/Timeline.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { Badge } from '../../components/Badge/Badge'\nimport { Heading } from '../../components/Heading/Heading'\nimport { Tag } from '../../components/Tag/Tag'\nimport { Text } from '../../components/Text/Text'\nimport { cn } from '../../lib/cn'\n\nexport interface RecordSectionProps extends HTMLAttributes<HTMLElement> {\n title: string\n count?: string\n headingId: string\n children: ReactNode\n}\n\n/** A named ledger section. The host supplies its chronology without reordering. */\nexport function RecordSection({ title, count, headingId, children, className, ...rest }: RecordSectionProps) {\n return <section aria-labelledby={headingId} className={cn('folio-record-section', className)} {...rest}><header className=\"folio-record-section__header\"><Heading level={2} id={headingId}>{title}</Heading>{count && <Text as=\"span\" size=\"xs\" tone=\"muted\">{count}</Text>}</header>{children}</section>\n}\n\nexport interface CareerRecordProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {\n title: string\n organization: ReactNode\n period: string\n periodLabel: string\n location: string\n locationLabel: string\n description: string[]\n tags: string[]\n tagsLabel: string\n mark?: ReactNode\n currentLabel?: string\n}\n\n/** One dated record, reusable for a role, qualification or other chronology. */\nexport function CareerRecord({ title, organization, period, periodLabel, location, locationLabel, description, tags, tagsLabel, mark, currentLabel, className, ...rest }: CareerRecordProps) {\n return (\n <article className={cn('folio-career-record', className)} {...rest}>\n <div className=\"folio-career-record__dates\"><dl><dt className=\"sr-only\">{periodLabel}</dt><dd><Text as=\"span\" size=\"sm\" tone=\"strong\">{period}</Text></dd><dt className=\"sr-only\">{locationLabel}</dt><dd><Text as=\"span\" size=\"xs\" tone=\"muted\">{location}</Text></dd></dl>{currentLabel && <Badge>{currentLabel}</Badge>}</div>\n <div className=\"folio-career-record__body\"><Heading level={3} size=\"heading\">{title}</Heading><div className=\"mt-2\">{organization}</div>{description.length === 1 && <Text className=\"mb-0 mt-5 max-w-(--measure-record)\">{description[0]}</Text>}{description.length > 1 && <ul className=\"folio-career-record__description\">{description.map((point, index) => <Text as=\"li\" key={index}>{point}</Text>)}</ul>}{tags.length > 0 && <ul aria-label={tagsLabel} className=\"folio-career-record__tags\">{tags.map((tag, index) => <li key={`${tag}-${index}`}><Tag>{tag}</Tag></li>)}</ul>}</div>\n {mark && <div className=\"folio-career-record__mark\">{mark}</div>}\n </article>\n )\n}\n\nexport interface ProfileSectionProps extends HTMLAttributes<HTMLElement> {\n headingId: string\n title: string\n description?: string\n children: ReactNode\n}\n\n/** A profile section follows the same heading and spacing contract as its neighbors. */\nexport function ProfileSection({ headingId, title, description, children, className, ...rest }: ProfileSectionProps) {\n return <section aria-labelledby={headingId} className={cn('folio-profile-section', className)} {...rest}><header className=\"folio-profile-section__header\"><Heading level={2} id={headingId}>{title}</Heading>{description && <Text className=\"m-0 max-w-[42rem]\">{description}</Text>}</header>{children}</section>\n}\n\nexport interface ProfileNarrativeProps {\n headingId: string\n title: string\n pull: string\n paragraphs: string[]\n action?: ReactNode\n}\n\n/** A short introduction with a pull quote and a longer account alongside it. */\nexport function ProfileNarrative({ headingId, title, pull, paragraphs, action }: ProfileNarrativeProps) {\n return <section aria-labelledby={headingId} className=\"folio-profile-narrative\"><div><Heading level={2} id={headingId}>{title}</Heading><Text size=\"lead\" tone=\"strong\" className=\"mb-0 mt-6 max-w-[30ch]\">{pull}</Text></div><div>{paragraphs.map((paragraph, index) => <Text key={index} className=\"mb-5 mt-0 max-w-(--measure-record)\">{paragraph}</Text>)}{action}</div></section>\n}\n\nexport interface ProfileSkill {\n id: string\n label: string\n icon?: ReactNode\n darkIcon?: ReactNode\n invertInDark?: boolean\n}\n\nexport interface ProfileSkillsProps {\n groups: { id: string; title: string; items: ProfileSkill[] }[]\n}\n\n/** Skill labels and theme-aware artwork, supplied by the host's content adapter. */\nexport function ProfileSkills({ groups }: ProfileSkillsProps) {\n return <div className=\"folio-profile-skills\">{groups.map((group) => <section className=\"folio-profile-skills__group\" key={group.id}><Heading level={3} size=\"item\">{group.title}</Heading><ul className=\"folio-profile-skills__items\">{group.items.map((skill) => <li key={skill.id}><span className=\"folio-profile-skill__icon\" data-invert={skill.invertInDark || undefined} data-has-dark={Boolean(skill.darkIcon) || undefined} aria-hidden><span data-artwork=\"light\">{skill.icon}</span>{skill.darkIcon && <span data-artwork=\"dark\">{skill.darkIcon}</span>}</span><Text as=\"span\" size=\"sm\" tone=\"strong\">{skill.label}</Text></li>)}</ul></section>)}</div>\n}\n\nexport interface ProfileInterestsProps {\n items: { id: string; title: string; description: string }[]\n}\n\n/** A small set of interests or areas of practice. */\nexport function ProfileInterests({ items }: ProfileInterestsProps) {\n return <div className=\"folio-profile-interests\">{items.map((item) => <article key={item.id}><Heading level={3}>{item.title}</Heading><Text className=\"mb-0 mt-4\">{item.description}</Text></article>)}</div>\n}\n\nexport interface ProfileFigureProps {\n children: ReactNode\n caption?: string\n}\n\n/** Source-faithful profile photography: retain the supplied image's aspect ratio. */\nexport function ProfileFigure({ children, caption }: ProfileFigureProps) {\n return <figure className=\"folio-profile-figure\"><div className=\"folio-profile-figure__image\">{children}</div>{caption && <Text as=\"figcaption\" size=\"xs\" tone=\"muted\" className=\"mt-3\">{caption}</Text>}</figure>\n}\n\n/** An ordered collection frame. No sorting or business data is owned here. */\nexport function Timeline({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('folio-timeline', className)} {...props} />\n}\n\n/** A record mount, isolated so motion can follow the shared data-motion axis. */\nexport function TimelineItem({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('folio-timeline__item', className)} {...props} />\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Timeline/Timeline.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { Badge } from '../../components/Badge/Badge'\nimport { Heading } from '../../components/Heading/Heading'\nimport { Tag } from '../../components/Tag/Tag'\nimport { Text } from '../../components/Text/Text'\nimport { cn } from '../../lib/cn'\n\nexport interface RecordSectionProps extends HTMLAttributes<HTMLElement> {\n title: string\n count?: string\n headingId: string\n children: ReactNode\n}\n\n/** A named ledger section. The host supplies its chronology without reordering. */\nexport function RecordSection({ title, count, headingId, children, className, ...rest }: RecordSectionProps) {\n return <section aria-labelledby={headingId} className={cn('folio-record-section', className)} {...rest}><header className=\"folio-record-section__header\"><Heading level={2} id={headingId}>{title}</Heading>{count && <Text as=\"span\" size=\"xs\" tone=\"muted\">{count}</Text>}</header>{children}</section>\n}\n\n/**\n * One entry in a record's tag row. A bare string is a text chip; an object can\n * add a mark beside the label. The mark is decoration — `aria-hidden` — so the\n * label is still the whole of what a screen reader hears.\n */\nexport type CareerRecordTag = string | { label: string; icon?: ReactNode }\n\nexport interface CareerRecordProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {\n title: string\n organization: ReactNode\n period: string\n periodLabel: string\n location: string\n locationLabel: string\n description: string[]\n tags: CareerRecordTag[]\n tagsLabel: string\n mark?: ReactNode\n currentLabel?: string\n}\n\n/** One dated record, reusable for a role, qualification or other chronology. */\nexport function CareerRecord({ title, organization, period, periodLabel, location, locationLabel, description, tags, tagsLabel, mark, currentLabel, className, ...rest }: CareerRecordProps) {\n return (\n <article className={cn('folio-career-record', className)} {...rest}>\n <div className=\"folio-career-record__dates\"><dl><dt className=\"sr-only\">{periodLabel}</dt><dd><Text as=\"span\" size=\"sm\" tone=\"strong\">{period}</Text></dd><dt className=\"sr-only\">{locationLabel}</dt><dd><Text as=\"span\" size=\"xs\" tone=\"muted\">{location}</Text></dd></dl>{currentLabel && <Badge>{currentLabel}</Badge>}</div>\n <div className=\"folio-career-record__body\"><Heading level={3} size=\"heading\">{title}</Heading><div className=\"mt-2\">{organization}</div>{description.length === 1 && <Text className=\"mb-0 mt-5 max-w-(--measure-record)\">{description[0]}</Text>}{description.length > 1 && <ul className=\"folio-career-record__description\">{description.map((point, index) => <Text as=\"li\" key={index}>{point}</Text>)}</ul>}{tags.length > 0 && <ul aria-label={tagsLabel} className=\"folio-career-record__tags\">{tags.map((tag, index) => { const { label, icon } = typeof tag === 'string' ? { label: tag, icon: undefined } : tag; return <li key={`${label}-${index}`}><Tag className=\"folio-career-record__tag\">{icon && <span aria-hidden=\"true\" className=\"folio-career-record__tag-mark\">{icon}</span>}{label}</Tag></li> })}</ul>}</div>\n {mark && <div className=\"folio-career-record__mark\">{mark}</div>}\n </article>\n )\n}\n\nexport interface ProfileSectionProps extends HTMLAttributes<HTMLElement> {\n headingId: string\n title: string\n description?: string\n children: ReactNode\n}\n\n/** A profile section follows the same heading and spacing contract as its neighbors. */\nexport function ProfileSection({ headingId, title, description, children, className, ...rest }: ProfileSectionProps) {\n return <section aria-labelledby={headingId} className={cn('folio-profile-section', className)} {...rest}><header className=\"folio-profile-section__header\"><Heading level={2} id={headingId}>{title}</Heading>{description && <Text className=\"m-0 max-w-[42rem]\">{description}</Text>}</header>{children}</section>\n}\n\nexport interface ProfileNarrativeProps {\n headingId: string\n title: string\n pull: string\n paragraphs: string[]\n action?: ReactNode\n}\n\n/** A short introduction with a pull quote and a longer account alongside it. */\nexport function ProfileNarrative({ headingId, title, pull, paragraphs, action }: ProfileNarrativeProps) {\n return <section aria-labelledby={headingId} className=\"folio-profile-narrative\"><div><Heading level={2} id={headingId}>{title}</Heading><Text size=\"lead\" tone=\"strong\" className=\"mb-0 mt-6 max-w-[30ch]\">{pull}</Text></div><div>{paragraphs.map((paragraph, index) => <Text key={index} className=\"mb-5 mt-0 max-w-(--measure-record)\">{paragraph}</Text>)}{action}</div></section>\n}\n\nexport interface ProfileSkill {\n id: string\n label: string\n icon?: ReactNode\n darkIcon?: ReactNode\n invertInDark?: boolean\n}\n\nexport interface ProfileSkillsProps {\n groups: { id: string; title: string; items: ProfileSkill[] }[]\n}\n\n/** Skill labels and theme-aware artwork, supplied by the host's content adapter. */\nexport function ProfileSkills({ groups }: ProfileSkillsProps) {\n return <div className=\"folio-profile-skills\">{groups.map((group) => <section className=\"folio-profile-skills__group\" key={group.id}><Heading level={3} size=\"item\">{group.title}</Heading><ul className=\"folio-profile-skills__items\">{group.items.map((skill) => <li key={skill.id}><span className=\"folio-profile-skill__icon\" data-invert={skill.invertInDark || undefined} data-has-dark={Boolean(skill.darkIcon) || undefined} aria-hidden><span data-artwork=\"light\">{skill.icon}</span>{skill.darkIcon && <span data-artwork=\"dark\">{skill.darkIcon}</span>}</span><Text as=\"span\" size=\"sm\" tone=\"strong\">{skill.label}</Text></li>)}</ul></section>)}</div>\n}\n\nexport interface ProfileInterestsProps {\n items: { id: string; title: string; description: string }[]\n}\n\n/** A small set of interests or areas of practice. */\nexport function ProfileInterests({ items }: ProfileInterestsProps) {\n return <div className=\"folio-profile-interests\">{items.map((item) => <article key={item.id}><Heading level={3}>{item.title}</Heading><Text className=\"mb-0 mt-4\">{item.description}</Text></article>)}</div>\n}\n\nexport interface ProfileFigureProps {\n children: ReactNode\n caption?: string\n}\n\n/** Source-faithful profile photography: retain the supplied image's aspect ratio. */\nexport function ProfileFigure({ children, caption }: ProfileFigureProps) {\n return <figure className=\"folio-profile-figure\"><div className=\"folio-profile-figure__image\">{children}</div>{caption && <Text as=\"figcaption\" size=\"xs\" tone=\"muted\" className=\"mt-3\">{caption}</Text>}</figure>\n}\n\n/** An ordered collection frame. No sorting or business data is owned here. */\nexport function Timeline({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('folio-timeline', className)} {...props} />\n}\n\n/** A record mount, isolated so motion can follow the shared data-motion axis. */\nexport function TimelineItem({ className, ...props }: HTMLAttributes<HTMLDivElement>) {\n return <div className={cn('folio-timeline__item', className)} {...props} />\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A preset is a combination of theme axes, never a block of its own, so this
|
|
5
5
|
* is the whole of it: linen ground and warm ink, an ember accent for links and
|
|
6
|
-
* the current state, primary buttons in ink, headings in the grotesk at a quiet voice, and quiet rules. Radius, motion
|
|
6
|
+
* the current state, primary buttons in ink and every control a capsule, headings in the grotesk at a quiet voice, and quiet rules. Radius, motion
|
|
7
7
|
* and density stay on their defaults. Spread it onto the root element:
|
|
8
8
|
*
|
|
9
9
|
* ```tsx
|
|
@@ -17,6 +17,7 @@ declare const WORKBENCH_THEME: {
|
|
|
17
17
|
readonly 'data-type': "grotesk";
|
|
18
18
|
readonly 'data-rules': "quiet";
|
|
19
19
|
readonly 'data-voice': "quiet";
|
|
20
|
+
readonly 'data-controls': "pill";
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export { WORKBENCH_THEME };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/website/Workbench/theme.ts"],"sourcesContent":["/**\n * The Workbench preset as the attributes a host writes on `<html>`.\n *\n * A preset is a combination of theme axes, never a block of its own, so this\n * is the whole of it: linen ground and warm ink, an ember accent for links and\n * the current state, primary buttons in ink, headings in the grotesk at a quiet voice, and quiet rules. Radius, motion\n * and density stay on their defaults. Spread it onto the root element:\n *\n * ```tsx\n * <html {...WORKBENCH_THEME} data-mode=\"light\">\n * ```\n */\nexport const WORKBENCH_THEME = {\n 'data-surface': 'linen',\n 'data-accent': 'ember',\n 'data-action': 'ink',\n 'data-type': 'grotesk',\n 'data-rules': 'quiet',\n 'data-voice': 'quiet',\n} as const\n"],"mappings":"AAYO,MAAM,kBAAkB;AAAA,EAC7B,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;
|
|
1
|
+
{"version":3,"sources":["../../../src/website/Workbench/theme.ts"],"sourcesContent":["/**\n * The Workbench preset as the attributes a host writes on `<html>`.\n *\n * A preset is a combination of theme axes, never a block of its own, so this\n * is the whole of it: linen ground and warm ink, an ember accent for links and\n * the current state, primary buttons in ink and every control a capsule, headings in the grotesk at a quiet voice, and quiet rules. Radius, motion\n * and density stay on their defaults. Spread it onto the root element:\n *\n * ```tsx\n * <html {...WORKBENCH_THEME} data-mode=\"light\">\n * ```\n */\nexport const WORKBENCH_THEME = {\n 'data-surface': 'linen',\n 'data-accent': 'ember',\n 'data-action': 'ink',\n 'data-type': 'grotesk',\n 'data-rules': 'quiet',\n 'data-voice': 'quiet',\n 'data-controls': 'pill',\n} as const\n"],"mappings":"AAYO,MAAM,kBAAkB;AAAA,EAC7B,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,cAAc;AAAA,EACd,cAAc;AAAA,EACd,iBAAiB;AACnB;","names":[]}
|
package/dist/website/index.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ export { Portfolio, PortfolioCategories, PortfolioCategoriesProps, PortfolioImag
|
|
|
4
4
|
export { QuestionCard, QuestionCardProps } from './Portfolio/QuestionCard.js';
|
|
5
5
|
export { PortfolioIndex, PortfolioIndexItem, PortfolioIndexProps } from './PortfolioIndex/PortfolioIndex.js';
|
|
6
6
|
export { CollectionControls, CollectionControlsProps, CollectionEmpty, CollectionEmptyProps, CollectionFilter, CollectionFooter, CollectionFooterProps, CollectionGroup, CollectionGroupProps, CollectionIntro, CollectionIntroProps, CollectionLink, CollectionList, CollectionListProps, CollectionMetadata, CollectionMetadataItem, CollectionMetadataProps, CollectionSearch, CollectionSearchProps, CollectionTally, CollectionTallyProps, ContentBand, ContentBandProps, FeaturedRecord, FeaturedRecordProps, HighlightedText, HighlightedTextProps, RecordRow, RecordRowProps, ReferenceLink, ReferenceRows, ReferenceRowsProps, TaxonomyLinks, TaxonomyLinksProps } from './Collection/Collection.js';
|
|
7
|
-
export { ActionBand, ActionBandProps, ArchitectureColumnNode, ArchitectureColumns, ArchitectureColumnsProps, AuthorPanel, AuthorPanelProps, CommandPiece, CommandSnippet, CommandSnippetProps, CommandTab, CommandTabs, CommandTabsProps, ContentFigure, ContentFigureProps, DetailMasthead, DetailMastheadProps, DevicePreview, DevicePreviewProps, FeaturePairs, FeaturePairsProps, MediaPlayback, MediaPlaybackProps, MobileOutline, MobileOutlineProps, OutlineItem, PreviewPair, PreviewPairProps, ReadingFigure, ReadingFigureProps, ReadingForm, ReadingFormProps, ReadingLayout, ReadingLayoutProps, ReadingLead, ReadingLeadProps, ReadingMetadataItem, ReadingPage, ReadingPageProps, ReadingPagerItem, ReadingProgress, ReadingSection, ReadingSectionProps, ReadingSurface, ReadingSurfaceProps, RecordPager, RecordPagerProps, TableOfContents, TableOfContentsProps, TokenLine, TokenLineProps, isSelfNumbered, numberToc } from './Reading/Reading.js';
|
|
7
|
+
export { ActionBand, ActionBandProps, ArchitectureColumnNode, ArchitectureColumns, ArchitectureColumnsProps, AuthorPanel, AuthorPanelProps, CommandPiece, CommandSnippet, CommandSnippetProps, CommandTab, CommandTabs, CommandTabsProps, ContentFigure, ContentFigureProps, DetailMasthead, DetailMastheadProps, DevicePreview, DevicePreviewProps, DeviceRow, DeviceRowProps, FeaturePairs, FeaturePairsProps, MediaPlayback, MediaPlaybackProps, MobileOutline, MobileOutlineProps, OutlineItem, PreviewPair, PreviewPairProps, ReadingFigure, ReadingFigureProps, ReadingForm, ReadingFormProps, ReadingLayout, ReadingLayoutProps, ReadingLead, ReadingLeadProps, ReadingMetadataItem, ReadingPage, ReadingPageProps, ReadingPagerItem, ReadingProgress, ReadingSection, ReadingSectionProps, ReadingSurface, ReadingSurfaceProps, RecordPager, RecordPagerProps, TableOfContents, TableOfContentsProps, TokenLine, TokenLineProps, isSelfNumbered, numberToc } from './Reading/Reading.js';
|
|
8
8
|
export { ContactFacts, ContactFactsProps, ContactFormLabels, ContactFormValues, ContactFormView, ContactFormViewProps, CorrespondenceSection, CorrespondenceSectionProps, LocationFigure, LocationFigureProps, QuestionList, QuestionListProps } from './Contact/Contact.js';
|
|
9
9
|
export { MediaCollectionCard, MediaCollectionCardProps, MediaListRow, MediaListRowProps, MediaPreviewAction, MusicFeature, MusicFeatureProps, MusicSection, MusicSectionProps } from './Music/Music.js';
|
|
10
|
-
export { CareerRecord, CareerRecordProps, ProfileFigure, ProfileFigureProps, ProfileInterests, ProfileInterestsProps, ProfileNarrative, ProfileNarrativeProps, ProfileSection, ProfileSectionProps, ProfileSkill, ProfileSkills, ProfileSkillsProps, RecordSection, RecordSectionProps, Timeline, TimelineItem } from './Timeline/Timeline.js';
|
|
10
|
+
export { CareerRecord, CareerRecordProps, CareerRecordTag, ProfileFigure, ProfileFigureProps, ProfileInterests, ProfileInterestsProps, ProfileNarrative, ProfileNarrativeProps, ProfileSection, ProfileSectionProps, ProfileSkill, ProfileSkills, ProfileSkillsProps, RecordSection, RecordSectionProps, Timeline, TimelineItem } from './Timeline/Timeline.js';
|
|
11
11
|
export { LoadingRecords, LoadingRecordsProps, LoadingRouteIntro, LoadingRouteIntroProps, RecoveryLinks, RecoveryLinksProps, RecoveryState, RecoveryStateProps, WebsiteLoading, WebsiteLoadingProps } from './Recovery/Recovery.js';
|
|
12
12
|
export { MediaCollection, MediaCollectionProps, MediaDetailLayout, MediaDetailLayoutProps, MediaGallery, MediaGalleryItem, MediaGalleryItemProps, MediaGalleryProps, MediaGallerySkeleton, MediaGallerySkeletonProps, MediaLightNote, MediaLightNoteLine, MediaLightNoteProps, MediaMapArea, MediaMapAreaList, MediaMapAreaListProps, MediaMapCanvas, MediaMapCanvasProps, MediaMapFrame, MediaMapFrameProps, MediaMapMarker, MediaMapMarkerProps, MediaMapNavigation, MediaMapNavigationProps, MediaMapPin, MediaMapPinProps, MediaMapPreview, MediaMapPreviewProps, MediaMapSection, MediaMapSectionProps, MediaMapSkeleton, MediaMasthead, MediaMastheadProps, MediaMetadata, MediaMetadataProps, MediaPager, MediaPagerItem, MediaPagerItemProps, MediaPagerProps, MediaThumbnail, MediaThumbnailProps, MediaThumbnailStrip, MediaThumbnailStripProps, PhotographFeature, PhotographFeatureProps } from './Media/Media.js';
|
|
13
13
|
export { MediaLightbox, MediaLightboxProps } from './Media/MediaLightbox.js';
|
package/dist/website-media.css
CHANGED
|
@@ -125,15 +125,21 @@
|
|
|
125
125
|
.folio-media-pager-link[data-direction='next'] { grid-template-columns: minmax(0, 1fr) 4.5rem; padding-inline: 1.5rem 0; }
|
|
126
126
|
.folio-media-pager-copy { min-inline-size: 0; }
|
|
127
127
|
.folio-media-pager-link[data-direction='next'] .folio-media-pager-copy { text-align: end; }
|
|
128
|
-
.folio-media-pager-image { position: relative; display: block; block-size: 3.25rem; overflow: hidden; background: var(--background-elevated); }
|
|
129
|
-
.folio-media-pager-image img { object-fit:
|
|
128
|
+
.folio-media-pager-image { position: relative; display: block; block-size: 3.25rem; overflow: hidden; border-radius: var(--radius-sm); background: var(--background-elevated); }
|
|
129
|
+
.folio-media-pager-image img { object-fit: cover; }
|
|
130
130
|
.folio-media-pager-label { display: block; color: var(--secondary-text); font-family: var(--label-font); font-size: 0.625rem; letter-spacing: calc(0.16em * var(--label-tracking-scale)); text-transform: var(--label-case); }
|
|
131
131
|
.folio-media-pager-title { display: block; overflow: hidden; margin-block-start: 0.3125rem; color: var(--foreground); font-family: var(--font-heading); font-size: 1.0625rem; font-weight: var(--display-weight); line-height: 1.2; text-overflow: ellipsis; white-space: nowrap; }
|
|
132
132
|
.folio-media-thumbnails { padding-block-start: clamp(1.5rem, 3vw, 2.5rem); border-block-start: 1px solid var(--border-subtle); }
|
|
133
133
|
.folio-media-thumbnails h2 { margin-block: 0 0.75rem; color: var(--foreground-muted); font-family: var(--label-font); font-size: 0.6875rem; font-weight: 400; letter-spacing: calc(0.13em * var(--label-tracking-scale)); text-transform: var(--label-case); }
|
|
134
134
|
.folio-media-thumbnail-list { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: clamp(0.4rem, 1vw, 0.8rem); }
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
/* Each frame fills its square. `contain` letterboxed every photograph onto an
|
|
136
|
+
elevated plate, so a strip of mixed orientations read as a row of grey
|
|
137
|
+
cards on a linen page — two grounds for one set of images. Cropped, the
|
|
138
|
+
plate only shows for the instant before the image decodes. */
|
|
139
|
+
.folio-media-thumbnail { position: relative; display: block; min-inline-size: 44px; min-block-size: 44px; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius); background: var(--background-elevated); }
|
|
140
|
+
.folio-media-thumbnail img { object-fit: cover; transition: scale var(--duration-base) var(--ease), opacity var(--duration-base) var(--ease); }
|
|
141
|
+
.folio-media-thumbnail:hover img { scale: 1.02; }
|
|
142
|
+
@media (prefers-reduced-motion: reduce) { .folio-media-thumbnail img { transition: none; } .folio-media-thumbnail:hover img { scale: none; } }
|
|
137
143
|
|
|
138
144
|
.folio-media-map-section { border-block: 1px solid var(--border-subtle); background: var(--background-elevated); padding-block: clamp(4rem, 10vw, 8rem); }
|
|
139
145
|
.folio-media-anchor { display: block; block-size: 0; scroll-margin-block-start: var(--scroll-offset); pointer-events: none; }
|
package/dist/website-reading.css
CHANGED
|
@@ -47,7 +47,10 @@
|
|
|
47
47
|
.folio-toc a[aria-current=true]{font-weight:500;color:var(--ink)}
|
|
48
48
|
.folio-toc a:hover{color:var(--ink)}
|
|
49
49
|
.folio-toc a>span{font-family:var(--mono-i18n,var(--font-mono));font-size:.625rem}
|
|
50
|
-
|
|
50
|
+
/* The outline trigger stacks one step above the conversation launcher, which
|
|
51
|
+
owns the same corner (1.5rem in, 3rem tall). Sharing the spot put one
|
|
52
|
+
control on top of the other on every narrow article page. */
|
|
53
|
+
.folio-outline-trigger{position:fixed;inset-inline-start:1.5rem;inset-block-end:calc(1.5rem + 3rem + .75rem);z-index:var(--z-sticky,30)}
|
|
51
54
|
.folio-outline-sheet .folio-toc a{min-height:44px}
|
|
52
55
|
.folio-reading-progress{position:fixed;inset-block-start:0;inset-inline:0;z-index:var(--z-sticky,30);height:2px;pointer-events:none}
|
|
53
56
|
.folio-reading-progress>div{height:100%;background:var(--accent)}
|
|
@@ -86,9 +89,17 @@
|
|
|
86
89
|
.folio-browser-bar>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
87
90
|
.folio-device-screen{position:relative;aspect-ratio:16/10;overflow:hidden}
|
|
88
91
|
.folio-device-screen img{width:100%;height:100%;object-fit:cover}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
.
|
|
92
|
+
/* The phone is an iPhone as the Simulator draws it: a dark bezel with a
|
|
93
|
+
hairline rim, a screen whose corner follows the glass, and the Dynamic Island
|
|
94
|
+
over the status bar. It used to be the browser frame with thicker borders —
|
|
95
|
+
a rounded rectangle that read as a box around a screenshot, not a device. */
|
|
96
|
+
.folio-device-preview[data-kind=phone]{max-width:16.5rem;justify-self:center}
|
|
97
|
+
.folio-device-preview[data-kind=phone]>div{position:relative;padding:.5rem;border:0;border-radius:2.75rem;background:var(--device-bezel);box-shadow:0 0 0 1px var(--device-rim),0 1.5rem 3rem color-mix(in srgb,var(--device-island) 22%,transparent)}
|
|
98
|
+
.folio-device-preview[data-kind=phone]>div::before{content:'';position:absolute;z-index:1;inset-block-start:1.125rem;inset-inline-start:50%;inline-size:31%;block-size:1.6rem;translate:-50% 0;border-radius:var(--radius-pill);background:var(--device-island)}
|
|
99
|
+
.folio-device-preview[data-kind=phone] .folio-device-screen{aspect-ratio:393/852;overflow:hidden;border-radius:2.25rem;background:var(--device-island)}
|
|
100
|
+
.folio-device-preview[data-kind=phone] figcaption{text-align:center}
|
|
101
|
+
.folio-device-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,12.5rem),1fr));gap:clamp(1.5rem,4vw,3rem);align-items:end;padding-block:1.75rem .5rem}
|
|
102
|
+
@media(min-width:48rem){.folio-device-row>:nth-child(3n+2){margin-block-end:2.5rem}}
|
|
92
103
|
.folio-device-preview figcaption{font-family:var(--mono-i18n,var(--font-mono));font-size:.6875rem;color:var(--ink-3-aa);margin-block-start:.75rem}
|
|
93
104
|
.folio-command-tabs{min-width:0}
|
|
94
105
|
.folio-command-tabs [role=tablist]{flex-wrap:wrap}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/* The wait-then-fade every route skeleton shares. The delay is one fast step:
|
|
2
|
+
a route that answers inside it never shows a skeleton at all, and one that
|
|
3
|
+
does not fades the bars in instead of cutting to them. The pulse lives on
|
|
4
|
+
the SkeletonPage inside, so the two animations never fight for a property. */
|
|
5
|
+
.folio-loading-page { animation: folio-loading-in var(--duration-base) var(--ease) var(--duration-fast) both; }
|
|
6
|
+
@keyframes folio-loading-in { from { opacity: 0; } to { opacity: 1; } }
|
|
7
|
+
@media (prefers-reduced-motion: reduce) { .folio-loading-page { animation: none; } }
|
|
1
8
|
.folio-recovery-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; }
|
|
2
9
|
.folio-recovery-links { margin-block: clamp(3.5rem, 7vw, 6rem) 3rem; }
|
|
3
10
|
.folio-recovery-links ul { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 4rem; margin: .25rem 0 0; padding: 0; list-style: none; }
|
|
@@ -12,6 +19,7 @@
|
|
|
12
19
|
.folio-loading-media { border-block: 1px solid var(--rule); background: var(--paper-2); }
|
|
13
20
|
.folio-loading-metrics__figures { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-block: 1px solid var(--rule); }
|
|
14
21
|
.folio-loading-metrics__figures > div { padding: clamp(1.5rem, 4vw, 2.25rem) clamp(1rem, 3vw, 1.625rem); }
|
|
22
|
+
.folio-loading-article { padding-block-start: clamp(4rem, 8vw, 6rem); }
|
|
15
23
|
.folio-loading-identity { display: grid; align-items: center; gap: 3.5rem; padding-block: clamp(7rem, 9vw, 8rem) clamp(2.5rem, 5vw, 4rem); }
|
|
16
24
|
@media (min-width: 640px) {
|
|
17
25
|
.folio-recovery-links ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
package/dist/website-search.css
CHANGED
|
@@ -1,26 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/* The panel: one surface, a hairline, and the lift a floating layer is
|
|
2
|
+
allowed. The field is part of the panel rather than a grey band on top of
|
|
3
|
+
it, and the list below it is single-line rows at the 44px target. */
|
|
4
|
+
.folio-search-palette { border-color: var(--rule); background: var(--paper); }
|
|
5
|
+
.folio-search-palette__search { position: relative; display: flex; align-items: center; border-block-end: 1px solid var(--rule); }
|
|
6
|
+
.folio-search-palette__search [cmdk-input-wrapper], .folio-search-palette__search > div:first-child { flex: 1; min-inline-size: 0; border: 0; }
|
|
7
|
+
.folio-search-palette__search input { block-size: 3.5rem; padding-inline-end: 3rem; font-size: .9375rem; }
|
|
4
8
|
.folio-search-palette__search input:focus, .folio-search-palette__search input:focus-visible,
|
|
5
9
|
.folio-search-palette__input input:focus, .folio-search-palette__input input:focus-visible { outline: none; box-shadow: none; }
|
|
6
10
|
.folio-search-palette__close { position: absolute; inset-block-start: 50%; inset-inline-end: .5rem; translate: 0 -50%; }
|
|
7
|
-
.folio-search-palette__input { display: flex; align-items: center; gap: .5rem; padding: .75rem; border-block-end: 1px solid var(--rule); }
|
|
11
|
+
.folio-search-palette__input { display: flex; align-items: center; gap: .5rem; padding: .625rem .75rem; border-block-end: 1px solid var(--rule); }
|
|
8
12
|
.folio-search-palette__input input { min-inline-size: 0; }
|
|
9
|
-
.folio-search-palette__detail { max-block-size: calc(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
.folio-search-
|
|
13
|
-
.folio-search-
|
|
14
|
-
.folio-search-
|
|
13
|
+
.folio-search-palette__detail { max-block-size: calc(70svh - 6.5rem); overflow-y: auto; overscroll-behavior: contain; padding: 1.5rem; }
|
|
14
|
+
/* The last visible row dissolves into the footer rather than being sliced by
|
|
15
|
+
it, which is what tells a reader the list goes on. */
|
|
16
|
+
.folio-search-palette [cmdk-list] { padding: .375rem; mask-image: linear-gradient(to bottom, #000 calc(100% - 1.5rem), transparent); }
|
|
17
|
+
.folio-search-palette [cmdk-group-heading] { padding: .75rem .625rem .375rem; }
|
|
18
|
+
.folio-search-palette__heading { color: var(--ink-3-aa); font-family: var(--sans); font-size: .75rem; letter-spacing: normal; text-transform: none; }
|
|
19
|
+
.folio-search-palette__item { min-block-size: 2.75rem; margin: 0; padding-block: .5rem; border-radius: var(--radius-row); font-size: .875rem; }
|
|
15
20
|
.folio-search-palette__item::before { display: none; }
|
|
16
|
-
.folio-search-palette__item[data-selected=true] { background: var(--paper-2);
|
|
17
|
-
.folio-search-
|
|
21
|
+
.folio-search-palette__item[data-selected=true] { background: var(--paper-2); }
|
|
22
|
+
.folio-search-palette__result { flex: 1; min-inline-size: 0; display: flex; align-items: baseline; gap: .625rem; }
|
|
23
|
+
.folio-search-palette__result > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
24
|
+
.folio-search-palette__result > span:first-child { flex: none; max-inline-size: 70%; color: var(--ink); }
|
|
25
|
+
.folio-search-palette__description { flex: 1; min-inline-size: 0; color: var(--ink-3-aa); font-size: .8125rem; }
|
|
26
|
+
.folio-search-palette__meta { font-family: var(--sans); font-size: .6875rem; opacity: 0; transition: opacity var(--duration-fast) var(--ease); }
|
|
18
27
|
.folio-search-palette__item[data-selected=true] .folio-search-palette__meta { opacity: 1; }
|
|
19
|
-
.folio-search-palette__highlight { color: var(--ink); background: var(--stone); border-radius: var(--radius-
|
|
20
|
-
.folio-search-palette__footer { flex-wrap: wrap; }
|
|
28
|
+
.folio-search-palette__highlight { color: var(--ink); background: var(--stone); border-radius: var(--radius-xs); }
|
|
29
|
+
.folio-search-palette__footer { flex-wrap: wrap; border-block-start: 1px solid var(--rule); background: var(--paper); }
|
|
21
30
|
@media (max-width: 40rem) {
|
|
22
31
|
.folio-search-palette__search input { font-size: 1rem; }
|
|
23
32
|
.folio-search-palette__detail { max-block-size: calc(84svh - 4.5rem); }
|
|
33
|
+
.folio-search-palette__result { display: grid; gap: .125rem; }
|
|
34
|
+
.folio-search-palette__result > span:first-child { max-inline-size: none; }
|
|
24
35
|
.folio-search-palette__meta { display: none; }
|
|
25
36
|
.folio-search-palette__footer { display: none; }
|
|
26
37
|
}
|
|
38
|
+
@media (prefers-reduced-motion: reduce) {
|
|
39
|
+
.folio-search-palette { animation: none !important; }
|
|
40
|
+
}
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
.folio-career-record__description { margin-block: 1.25rem 0; max-inline-size: var(--measure-record); padding-inline-start: 1.25rem; list-style: disc; }
|
|
10
10
|
.folio-career-record__description > li + li { margin-block-start: .5rem; }
|
|
11
11
|
.folio-career-record__tags { display: flex; flex-wrap: wrap; gap: .5rem; margin-block: 1.25rem 0; list-style: none; padding: 0; }
|
|
12
|
+
/* Every chip in the row is the same flex box, marked or not, so a text-only
|
|
13
|
+
chip shares its neighbours' baseline. A mark takes the label's colour, so a
|
|
14
|
+
row of brand marks reads as one quiet line rather than a sticker sheet. */
|
|
15
|
+
.folio-career-record__tag { display: inline-flex; align-items: center; gap: .375rem; }
|
|
16
|
+
.folio-career-record__tag-mark { display: inline-flex; flex: none; inline-size: .875rem; block-size: .875rem; color: var(--ink-3-aa); }
|
|
17
|
+
.folio-career-record__tag-mark > :is(svg, img) { inline-size: 100%; block-size: 100%; }
|
|
12
18
|
.folio-career-record__mark { display: none; }
|
|
13
19
|
.folio-career-record__mark img { inline-size: 4rem; block-size: 4rem; object-fit: contain; }
|
|
14
20
|
.folio-profile-section, .folio-profile-narrative { padding-block: clamp(3rem, 6vw, 5rem); }
|
package/package.json
CHANGED
|
@@ -71,6 +71,7 @@ not just `:root`. An unset axis is the default.
|
|
|
71
71
|
| `data-type` | `grotesk` `bookish` | editorial |
|
|
72
72
|
| `data-motion` | `still` `snappy` | calm |
|
|
73
73
|
| `data-voice` | `quiet` | display |
|
|
74
|
+
| `data-controls` | `pill` | the control step (`--radius`) |
|
|
74
75
|
| `data-density` | `compact` | comfortable |
|
|
75
76
|
|
|
76
77
|
```tsx
|