@scalepad/ui 0.1.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/.ai/rules/date-handling.md +39 -0
- package/.ai/rules/figma-design-system.md +372 -0
- package/.ai/rules/figma-lm-design-system-keys.md +680 -0
- package/.ai/rules/file-extensions.md +13 -0
- package/.ai/rules/modal-confirmation-mutation.md +56 -0
- package/.ai/rules/react-hooks.md +29 -0
- package/.ai/rules/styling.md +83 -0
- package/AGENTS.md +37 -0
- package/README.md +125 -0
- package/figma.config.json +9 -0
- package/package.json +127 -0
- package/scripts/install-ai-rules.mjs +136 -0
- package/src/ThemeProvider.tsx +57 -0
- package/src/charts.ts +32 -0
- package/src/components/ActionCard/ActionCard.css.ts +60 -0
- package/src/components/ActionCard/ActionCard.tsx +154 -0
- package/src/components/ActionCard/index.ts +2 -0
- package/src/components/Anchor/Anchor.tsx +47 -0
- package/src/components/Anchor/index.ts +2 -0
- package/src/components/AppliedFiltersManagerBar/AppliedFiltersManagerBar.tsx +105 -0
- package/src/components/AppliedFiltersManagerBar/FilterBadge.css.ts +23 -0
- package/src/components/AppliedFiltersManagerBar/FilterBadge.tsx +50 -0
- package/src/components/AppliedFiltersManagerBar/index.ts +5 -0
- package/src/components/Badge/Badge.css.ts +72 -0
- package/src/components/Badge/Badge.figma.tsx +43 -0
- package/src/components/Badge/Badge.tsx +159 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/BreadCrumb/BreadCrumb.tsx +62 -0
- package/src/components/BreadCrumb/index.ts +2 -0
- package/src/components/BulkActionBar/BulkActionBar.css.ts +26 -0
- package/src/components/BulkActionBar/BulkActionBar.tsx +164 -0
- package/src/components/BulkActionBar/index.ts +2 -0
- package/src/components/Button/Button.css.ts +272 -0
- package/src/components/Button/Button.figma.tsx +74 -0
- package/src/components/Button/Button.tsx +84 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Charts/ChartTooltip.figma.tsx +33 -0
- package/src/components/Charts/ChartTooltip.tsx +101 -0
- package/src/components/Charts/MiniBarSparkline.tsx +75 -0
- package/src/components/Charts/StackedPatternBarChart.tsx +494 -0
- package/src/components/Charts/TrendAreaChart.css.ts +23 -0
- package/src/components/Charts/TrendAreaChart.tsx +210 -0
- package/src/components/Charts/index.ts +12 -0
- package/src/components/CodePanel/CodePanel.css.ts +113 -0
- package/src/components/CodePanel/CodePanel.tsx +121 -0
- package/src/components/CodePanel/index.ts +2 -0
- package/src/components/CommentComposer/CommentComposer.css.ts +60 -0
- package/src/components/CommentComposer/CommentComposer.tsx +181 -0
- package/src/components/CommentComposer/index.ts +2 -0
- package/src/components/ConfirmationModal/ConfirmationModal.tsx +149 -0
- package/src/components/ConfirmationModal/index.ts +2 -0
- package/src/components/ConfirmationTooltip/ConfirmationTooltip.tsx +132 -0
- package/src/components/ConfirmationTooltip/index.ts +2 -0
- package/src/components/DataDialog.figma.tsx +33 -0
- package/src/components/DataDialog.tsx +46 -0
- package/src/components/DataTable/DataTable.tsx +1042 -0
- package/src/components/DataTable/RowExpandToggle.tsx +105 -0
- package/src/components/DataTable/RowGroupHeader.tsx +190 -0
- package/src/components/DataTable/createActionsColumn.tsx +86 -0
- package/src/components/DataTable/index.ts +25 -0
- package/src/components/DatePicker/CustomRangePicker.tsx +59 -0
- package/src/components/DatePicker/DateInput.tsx +329 -0
- package/src/components/DatePicker/DateNavigator.tsx +486 -0
- package/src/components/DatePicker/DatePicker.tsx +242 -0
- package/src/components/DatePicker/MonthlyRangePicker.tsx +231 -0
- package/src/components/DatePicker/QuarterlyRangePicker.tsx +224 -0
- package/src/components/DatePicker/QuickPicksSidebar.tsx +242 -0
- package/src/components/DatePicker/YearlyRangePicker.tsx +171 -0
- package/src/components/DatePicker/index.ts +7 -0
- package/src/components/DatePicker/types.ts +12 -0
- package/src/components/DesignSystemPrimitives/FluidGrid.tsx +44 -0
- package/src/components/DesignSystemPrimitives/InteractivePrimitives.tsx +177 -0
- package/src/components/DesignSystemPrimitives/LayoutPrimitives.tsx +220 -0
- package/src/components/DesignSystemPrimitives/LayoutPrimitives.types.tsx +15 -0
- package/src/components/DesignSystemPrimitives/SurfacePrimitives.tsx +46 -0
- package/src/components/DesignSystemPrimitives/index.ts +55 -0
- package/src/components/Details/Details.css.ts +74 -0
- package/src/components/Details/Details.tsx +140 -0
- package/src/components/Details/index.ts +2 -0
- package/src/components/DownloadCard/DownloadCard.css.ts +22 -0
- package/src/components/DownloadCard/DownloadCard.tsx +63 -0
- package/src/components/DownloadCard/index.ts +2 -0
- package/src/components/Drawer/Drawer.css.ts +32 -0
- package/src/components/Drawer/Drawer.tsx +236 -0
- package/src/components/Drawer/hooks/useDetailDrawer.ts +61 -0
- package/src/components/Drawer/hooks/useDetailDrawerNavigation.ts +125 -0
- package/src/components/Drawer/hooks/useDetailDrawerNavigationContext.ts +66 -0
- package/src/components/EditableRichText/EditableRichText.css.ts +72 -0
- package/src/components/EditableRichText/EditableRichText.tsx +324 -0
- package/src/components/EditableRichText/index.ts +2 -0
- package/src/components/EditableSelect/EditableSelect.css.ts +62 -0
- package/src/components/EditableSelect/EditableSelect.tsx +224 -0
- package/src/components/EditableSelect/index.ts +2 -0
- package/src/components/EditableText/EditableText.tsx +377 -0
- package/src/components/EditableText/index.ts +2 -0
- package/src/components/EmptyState/EmptyState.figma.tsx +33 -0
- package/src/components/EmptyState/EmptyState.tsx +230 -0
- package/src/components/EmptyState/index.ts +2 -0
- package/src/components/ErrorBoundary.tsx +135 -0
- package/src/components/ErrorState/ErrorState.tsx +197 -0
- package/src/components/ErrorState/index.ts +2 -0
- package/src/components/FeatureCard.tsx +42 -0
- package/src/components/FilterMenu/FilterMenu.figma.tsx +30 -0
- package/src/components/FilterMenu/FilterMenu.tsx +198 -0
- package/src/components/FilterMenu/FilterSubMenuTypes/BooleanFilterSubmenu.tsx +46 -0
- package/src/components/FilterMenu/FilterSubMenuTypes/SearchableFilterSubmenu.tsx +239 -0
- package/src/components/FilterMenu/FilterSubMenuTypes/index.ts +8 -0
- package/src/components/FilterMenu/defaultFilterSchemas.ts +63 -0
- package/src/components/FilterMenu/helpers.ts +115 -0
- package/src/components/FilterMenu/index.ts +35 -0
- package/src/components/FilterMenu/types.ts +101 -0
- package/src/components/IconButton/IconButton.css.ts +272 -0
- package/src/components/IconButton/IconButton.figma.tsx +47 -0
- package/src/components/IconButton/IconButton.tsx +72 -0
- package/src/components/IconButton/README.md +230 -0
- package/src/components/IconButton/index.ts +2 -0
- package/src/components/InfiniteScrollSentinel.tsx +86 -0
- package/src/components/InfiniteScrollTrigger.tsx +78 -0
- package/src/components/InfoCard.figma.tsx +47 -0
- package/src/components/InfoCard.tsx +216 -0
- package/src/components/KbdHint/KbdHint.tsx +23 -0
- package/src/components/KbdHint/index.ts +2 -0
- package/src/components/LabeledField/LabeledField.tsx +21 -0
- package/src/components/LabeledField/index.ts +2 -0
- package/src/components/LookupSelect/LookupSelect.css.ts +149 -0
- package/src/components/LookupSelect/LookupSelect.tsx +325 -0
- package/src/components/LookupSelect/index.ts +2 -0
- package/src/components/Menu/Menu.css.ts +89 -0
- package/src/components/Menu/Menu.tsx +105 -0
- package/src/components/Menu/index.ts +2 -0
- package/src/components/MessageBox/MessageBox.tsx +168 -0
- package/src/components/MessageBox/index.ts +2 -0
- package/src/components/MetricDisplay/MetricDisplay.tsx +55 -0
- package/src/components/MetricDisplay/index.ts +1 -0
- package/src/components/MultiSelect/MultiSelect.tsx +278 -0
- package/src/components/MultiSelect/index.ts +2 -0
- package/src/components/Notifications/Notifications.tsx +12 -0
- package/src/components/Notifications/README.md +93 -0
- package/src/components/Notifications/index.ts +4 -0
- package/src/components/Notifications/showToast.tsx +100 -0
- package/src/components/PropertyRow/PropertyRow.tsx +96 -0
- package/src/components/PropertyRow/index.ts +2 -0
- package/src/components/RadioTile/RadioTile.tsx +253 -0
- package/src/components/RadioTile/index.ts +2 -0
- package/src/components/RichText/FormattingToolbar.css.ts +69 -0
- package/src/components/RichText/FormattingToolbar.tsx +112 -0
- package/src/components/RichText/RichTextInline.css.ts +54 -0
- package/src/components/RichText/RichTextInline.tsx +318 -0
- package/src/components/RichText/formattingCommands.ts +181 -0
- package/src/components/RichText/formattingTypes.ts +34 -0
- package/src/components/RichText/index.ts +49 -0
- package/src/components/RichText/richTextExtensions.ts +111 -0
- package/src/components/RichText/richTextHelpers.ts +65 -0
- package/src/components/RichText/richTextImage.ts +253 -0
- package/src/components/RichText/richTextImageHandlers.ts +244 -0
- package/src/components/RichText/richTextProse.css.ts +261 -0
- package/src/components/RichTextEditor/RichTextEditor.css.ts +82 -0
- package/src/components/RichTextEditor/RichTextEditor.tsx +204 -0
- package/src/components/RichTextEditor/index.ts +2 -0
- package/src/components/RichTextView/RichTextView.css.ts +11 -0
- package/src/components/RichTextView/RichTextView.tsx +114 -0
- package/src/components/RichTextView/index.ts +2 -0
- package/src/components/Schedule/Schedule.tsx +35 -0
- package/src/components/SchedulePicker/SchedulePicker.css.ts +42 -0
- package/src/components/SchedulePicker/SchedulePicker.tsx +130 -0
- package/src/components/SchedulePicker/index.ts +2 -0
- package/src/components/SearchableList/types.ts +30 -0
- package/src/components/SearchableSubMenu/SearchableSubMenu.css.ts +25 -0
- package/src/components/SearchableSubMenu/SearchableSubMenu.tsx +139 -0
- package/src/components/SearchableSubMenu/index.ts +2 -0
- package/src/components/Select/README.md +114 -0
- package/src/components/Select/Select.css.ts +110 -0
- package/src/components/Select/Select.tsx +133 -0
- package/src/components/Select/index.ts +2 -0
- package/src/components/SelectCreatable/SelectCreatable.css.ts +16 -0
- package/src/components/SelectCreatable/SelectCreatable.tsx +203 -0
- package/src/components/SelectCreatable/index.ts +2 -0
- package/src/components/SettingsCard/SettingsCard.tsx +98 -0
- package/src/components/SettingsCard/index.ts +2 -0
- package/src/components/Sidebar/Sidebar.css.ts +91 -0
- package/src/components/Sidebar/Sidebar.tsx +129 -0
- package/src/components/Sidebar/index.ts +5 -0
- package/src/components/SimpleList/SimpleList.css.ts +12 -0
- package/src/components/SimpleList/SimpleList.tsx +44 -0
- package/src/components/SimpleList/index.ts +2 -0
- package/src/components/SimpleTable/SimpleTable.tsx +296 -0
- package/src/components/SimpleTable/index.ts +2 -0
- package/src/components/SlashRichTextEditor/SelectionBubbleMenu.css.ts +62 -0
- package/src/components/SlashRichTextEditor/SelectionBubbleMenu.tsx +85 -0
- package/src/components/SlashRichTextEditor/SlashCommandMenu.css.ts +124 -0
- package/src/components/SlashRichTextEditor/SlashCommandMenu.tsx +168 -0
- package/src/components/SlashRichTextEditor/SlashRichTextEditor.css.ts +81 -0
- package/src/components/SlashRichTextEditor/SlashRichTextEditor.tsx +538 -0
- package/src/components/SlashRichTextEditor/SlashSuggestionExtension.ts +48 -0
- package/src/components/SlashRichTextEditor/index.ts +13 -0
- package/src/components/SlashRichTextEditor/types.ts +48 -0
- package/src/components/StatCard/StatCard.css.ts +70 -0
- package/src/components/StatCard/StatCard.tsx +201 -0
- package/src/components/StatCard/index.ts +1 -0
- package/src/components/StatusBadge/StatusBadge.tsx +70 -0
- package/src/components/StatusBadge/index.ts +2 -0
- package/src/components/StatusIndicator/StatusIndicator.tsx +67 -0
- package/src/components/StatusIndicator/index.ts +6 -0
- package/src/components/SubNavigation/SubNavigation.css.ts +72 -0
- package/src/components/SubNavigation/SubNavigation.tsx +104 -0
- package/src/components/SubNavigation/index.ts +2 -0
- package/src/components/SuspenseLoader.tsx +22 -0
- package/src/components/Table/SortableColumnHeader.tsx +99 -0
- package/src/components/Table/TableSkeletonRows.figma.tsx +22 -0
- package/src/components/Table/TableSkeletonRows.tsx +113 -0
- package/src/components/Table/index.ts +9 -0
- package/src/components/TableActionsMenu.tsx +58 -0
- package/src/components/TableCard.tsx +29 -0
- package/src/components/TableContainer/TableContainer.tsx +86 -0
- package/src/components/TableContainer/index.ts +2 -0
- package/src/components/TableControlBar/TableControlBar.tsx +156 -0
- package/src/components/TableControlBar/TableSelectionButton.tsx +57 -0
- package/src/components/TableControlBar/index.ts +13 -0
- package/src/components/TableControlBar/useTableControlBar.tsx +314 -0
- package/src/components/TableSelection/TableSelection.tsx +43 -0
- package/src/components/TableSelection/index.ts +5 -0
- package/src/components/Tabs/README.md +76 -0
- package/src/components/Tabs/Tabs.css.ts +54 -0
- package/src/components/Tabs/Tabs.figma.tsx +47 -0
- package/src/components/Tabs/Tabs.tsx +96 -0
- package/src/components/Tabs/index.ts +8 -0
- package/src/components/TextInput/README.md +98 -0
- package/src/components/TextInput/SearchTextInput.figma.tsx +22 -0
- package/src/components/TextInput/SearchTextInput.tsx +150 -0
- package/src/components/TextInput/TextInput.figma.tsx +44 -0
- package/src/components/TextInput/TextInput.tsx +42 -0
- package/src/components/TextInput/index.ts +4 -0
- package/src/components/ThemeSwitcher.figma.tsx +28 -0
- package/src/components/ThemeSwitcher.tsx +69 -0
- package/src/components/TrendBadge/TrendBadge.tsx +76 -0
- package/src/components/TrendBadge/index.ts +2 -0
- package/src/components/TruncatedText.tsx +115 -0
- package/src/components/Typography/Text.tsx +74 -0
- package/src/components/Typography/Title.tsx +100 -0
- package/src/components/Typography/index.ts +4 -0
- package/src/geist-fonts.ts +48 -0
- package/src/hooks/index.ts +31 -0
- package/src/hooks/useFilters.ts +152 -0
- package/src/hooks/useInfiniteScroll.ts +62 -0
- package/src/hooks/usePlatform.ts +33 -0
- package/src/hooks/useServerTable.ts +495 -0
- package/src/hooks/useTableSelection.ts +102 -0
- package/src/hooks/useTableSort.ts +259 -0
- package/src/index.ts +483 -0
- package/src/mantine.ts +25 -0
- package/src/theme/mantineVars.ts +12 -0
- package/src/theme/themeContract.css.ts +131 -0
- package/src/theme/themeVars.ts +31 -0
- package/src/theme.ts +168 -0
- package/src/tokens/color-types.ts +107 -0
- package/src/tokens/colors.ts +243 -0
- package/src/tokens/index.ts +14 -0
- package/src/tokens/radius.ts +17 -0
- package/src/tokens/semantic-colors.ts +224 -0
- package/src/tokens/semantic-tokens-css.ts +53 -0
- package/src/tokens/shadows.ts +11 -0
- package/src/tokens/spacing.ts +20 -0
- package/src/tokens/text-styles.ts +179 -0
- package/src/tokens/typography.ts +40 -0
- package/src/tokens/zIndex.ts +27 -0
- package/src/types/mantine-theme.d.ts +17 -0
- package/src/types/tanstack-table.d.ts +22 -0
- package/src/utils/avatar.ts +150 -0
- package/src/utils/chartHelpers.ts +53 -0
- package/src/utils/color-props.ts +77 -0
- package/src/utils/createDesignComponent.tsx +104 -0
- package/src/utils/nestFlatRows.ts +111 -0
- package/src/utils/withStaticComponents.ts +6 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design System Text Component
|
|
3
|
+
*
|
|
4
|
+
* Uses a single `variant` prop to control all typography styling (font size,
|
|
5
|
+
* weight, line height, letter spacing) from Figma text-style tokens.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <Text variant="body1">Default body text</Text>
|
|
10
|
+
* <Text variant="body1.strong">Medium weight body text</Text>
|
|
11
|
+
* <Text variant="caption1" c="text.subdued.default">Small muted text</Text>
|
|
12
|
+
* <Text variant="monospaced">Code-like text</Text>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
forwardRef,
|
|
18
|
+
type CSSProperties,
|
|
19
|
+
type MouseEventHandler,
|
|
20
|
+
type ReactNode,
|
|
21
|
+
} from 'react';
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
Text as MantineText,
|
|
25
|
+
type TextProps as MantineTextProps,
|
|
26
|
+
} from '@mantine/core';
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
textStyleVariants,
|
|
30
|
+
type BodyVariant,
|
|
31
|
+
type TextStyleDefinition,
|
|
32
|
+
} from '../../tokens';
|
|
33
|
+
import { resolveColorToken } from '../../utils/color-props';
|
|
34
|
+
|
|
35
|
+
import type { TextColor } from '../../tokens';
|
|
36
|
+
|
|
37
|
+
/** Typography styling props that are controlled by the variant and should not be set directly */
|
|
38
|
+
type TypographyStyleProps = 'fw' | 'fz' | 'size' | 'lh' | 'ff' | 'lts' | 'fs';
|
|
39
|
+
|
|
40
|
+
export type TextProps = Omit<
|
|
41
|
+
MantineTextProps,
|
|
42
|
+
TypographyStyleProps | 'c' | 'children'
|
|
43
|
+
> & {
|
|
44
|
+
/** Text style variant from the design system. Defaults to 'body1'. */
|
|
45
|
+
variant?: BodyVariant;
|
|
46
|
+
/** Text color - accepts semantic text tokens or 'inherit' */
|
|
47
|
+
c?: TextColor | 'inherit';
|
|
48
|
+
children?: ReactNode;
|
|
49
|
+
onClick?: MouseEventHandler<HTMLDivElement>;
|
|
50
|
+
style?: CSSProperties;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const Text = forwardRef<HTMLParagraphElement, TextProps>(
|
|
54
|
+
({ variant = 'body1', c, ...rest }, ref) => {
|
|
55
|
+
const variantStyles: TextStyleDefinition = textStyleVariants[variant];
|
|
56
|
+
const resolvedC = resolveColorToken(c);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<MantineText
|
|
60
|
+
ref={ref}
|
|
61
|
+
fw={variantStyles.fontWeight}
|
|
62
|
+
fz={variantStyles.fontSize}
|
|
63
|
+
lh={variantStyles.lineHeight}
|
|
64
|
+
lts={variantStyles.letterSpacing}
|
|
65
|
+
ff={variantStyles.fontFamily}
|
|
66
|
+
tt={variantStyles.textTransform}
|
|
67
|
+
c={resolvedC}
|
|
68
|
+
{...rest}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
Text.displayName = 'Text';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design System Title Component
|
|
3
|
+
*
|
|
4
|
+
* Uses a single `variant` prop to control all typography styling from Figma
|
|
5
|
+
* text-style tokens. An optional `order` prop controls the HTML heading
|
|
6
|
+
* element independently from the visual style.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* <Title variant="heading1">Page Title</Title>
|
|
11
|
+
* <Title variant="heading2">Section Title</Title>
|
|
12
|
+
* <Title variant="heading2" order={1}>Visually h2, renders as h1</Title>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
Title as MantineTitle,
|
|
18
|
+
type TitleProps as MantineTitleProps,
|
|
19
|
+
type TitleOrder,
|
|
20
|
+
} from '@mantine/core';
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
textStyleVariants,
|
|
24
|
+
type HeadingVariant,
|
|
25
|
+
} from '../../tokens/text-styles';
|
|
26
|
+
import { resolveColorToken } from '../../utils/color-props';
|
|
27
|
+
|
|
28
|
+
import type { TextColor } from '../../tokens/color-types';
|
|
29
|
+
|
|
30
|
+
/** Typography styling props that are controlled by the variant and should not be set directly */
|
|
31
|
+
type TypographyStyleProps = 'fw' | 'fz' | 'size' | 'lh' | 'ff' | 'lts' | 'fs';
|
|
32
|
+
|
|
33
|
+
const variantToOrder: Record<HeadingVariant, TitleOrder> = {
|
|
34
|
+
heading1: 1,
|
|
35
|
+
heading2: 2,
|
|
36
|
+
heading3: 3,
|
|
37
|
+
heading4: 4,
|
|
38
|
+
heading5: 5,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type TitleProps = Omit<
|
|
42
|
+
MantineTitleProps,
|
|
43
|
+
TypographyStyleProps | 'c' | 'children' | 'order'
|
|
44
|
+
> & {
|
|
45
|
+
/** Heading style variant from the design system. */
|
|
46
|
+
variant?: HeadingVariant;
|
|
47
|
+
/** HTML heading element (h1-h6). Defaults to match the variant. */
|
|
48
|
+
order?: TitleOrder;
|
|
49
|
+
/** Title color - accepts semantic text tokens or 'inherit' */
|
|
50
|
+
c?: TextColor | 'inherit';
|
|
51
|
+
children?: React.ReactNode;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function resolveVariant(
|
|
55
|
+
variant: HeadingVariant | undefined,
|
|
56
|
+
order: TitleOrder | undefined,
|
|
57
|
+
): HeadingVariant {
|
|
58
|
+
if (variant) {
|
|
59
|
+
return variant;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (order === 1) {
|
|
63
|
+
return 'heading1';
|
|
64
|
+
}
|
|
65
|
+
if (order === 2) {
|
|
66
|
+
return 'heading2';
|
|
67
|
+
}
|
|
68
|
+
if (order === 3) {
|
|
69
|
+
return 'heading3';
|
|
70
|
+
}
|
|
71
|
+
if (order === 4) {
|
|
72
|
+
return 'heading4';
|
|
73
|
+
}
|
|
74
|
+
if (order === 5) {
|
|
75
|
+
return 'heading5';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return 'heading4';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function Title({ variant, order, c, ...rest }: TitleProps) {
|
|
82
|
+
const effectiveVariant = resolveVariant(variant, order);
|
|
83
|
+
const variantStyles = textStyleVariants[effectiveVariant];
|
|
84
|
+
const resolvedC = resolveColorToken(c);
|
|
85
|
+
const effectiveOrder = order ?? variantToOrder[effectiveVariant];
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<MantineTitle
|
|
89
|
+
order={effectiveOrder}
|
|
90
|
+
fw={variantStyles.fontWeight}
|
|
91
|
+
fz={variantStyles.fontSize}
|
|
92
|
+
lh={variantStyles.lineHeight}
|
|
93
|
+
lts={variantStyles.letterSpacing}
|
|
94
|
+
c={resolvedC}
|
|
95
|
+
{...rest}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
Title.displayName = 'Title';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Import Geist font files as URLs
|
|
2
|
+
import geistSansItalicFont from './assets/Geist-Italic[wght].ttf?url';
|
|
3
|
+
import geistSansFont from './assets/Geist[wght].ttf?url';
|
|
4
|
+
import geistMonoItalicFont from './assets/GeistMono-Italic[wght].ttf?url';
|
|
5
|
+
import geistMonoFont from './assets/GeistMono[wght].ttf?url';
|
|
6
|
+
|
|
7
|
+
// Inject @font-face rules (only once)
|
|
8
|
+
if (
|
|
9
|
+
typeof document !== 'undefined' &&
|
|
10
|
+
!document.getElementById('geist-fonts')
|
|
11
|
+
) {
|
|
12
|
+
const style = document.createElement('style');
|
|
13
|
+
style.id = 'geist-fonts';
|
|
14
|
+
style.textContent = `
|
|
15
|
+
@font-face {
|
|
16
|
+
font-family: 'Geist Sans';
|
|
17
|
+
src: url('${geistSansFont}') format('truetype');
|
|
18
|
+
font-weight: 100 900;
|
|
19
|
+
font-style: normal;
|
|
20
|
+
font-display: swap;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@font-face {
|
|
24
|
+
font-family: 'Geist Sans';
|
|
25
|
+
src: url('${geistSansItalicFont}') format('truetype');
|
|
26
|
+
font-weight: 100 900;
|
|
27
|
+
font-style: italic;
|
|
28
|
+
font-display: swap;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@font-face {
|
|
32
|
+
font-family: 'Geist Mono';
|
|
33
|
+
src: url('${geistMonoFont}') format('truetype');
|
|
34
|
+
font-weight: 100 900;
|
|
35
|
+
font-style: normal;
|
|
36
|
+
font-display: swap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@font-face {
|
|
40
|
+
font-family: 'Geist Mono';
|
|
41
|
+
src: url('${geistMonoItalicFont}') format('truetype');
|
|
42
|
+
font-weight: 100 900;
|
|
43
|
+
font-style: italic;
|
|
44
|
+
font-display: swap;
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
document.head.appendChild(style);
|
|
48
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { useFilters } from './useFilters';
|
|
2
|
+
export type { UseFiltersOptions, UseFiltersReturn } from './useFilters';
|
|
3
|
+
export { useDetailDrawer } from '../components/Drawer/hooks/useDetailDrawer';
|
|
4
|
+
export type {
|
|
5
|
+
DetailDrawerSearch,
|
|
6
|
+
UseDetailDrawerOptions,
|
|
7
|
+
UseDetailDrawerReturn,
|
|
8
|
+
} from '../components/Drawer/hooks/useDetailDrawer';
|
|
9
|
+
export { useDetailDrawerNavigation } from '../components/Drawer/hooks/useDetailDrawerNavigation';
|
|
10
|
+
export type {
|
|
11
|
+
UseDetailDrawerNavigationOptions,
|
|
12
|
+
UseDetailDrawerNavigationReturn,
|
|
13
|
+
} from '../components/Drawer/hooks/useDetailDrawerNavigation';
|
|
14
|
+
export { useDetailDrawerNavigationContext } from '../components/Drawer/hooks/useDetailDrawerNavigationContext';
|
|
15
|
+
export type {
|
|
16
|
+
DetailDrawerNavigationContext,
|
|
17
|
+
UseDetailDrawerNavigationContextOptions,
|
|
18
|
+
} from '../components/Drawer/hooks/useDetailDrawerNavigationContext';
|
|
19
|
+
export { useInfiniteScroll } from './useInfiniteScroll';
|
|
20
|
+
export type { UseInfiniteScrollOptions } from './useInfiniteScroll';
|
|
21
|
+
export { useServerTable } from './useServerTable';
|
|
22
|
+
export type {
|
|
23
|
+
ListResponse,
|
|
24
|
+
UseServerTableOptions,
|
|
25
|
+
UseServerTableReturn,
|
|
26
|
+
} from './useServerTable';
|
|
27
|
+
export { useTableSelection } from './useTableSelection';
|
|
28
|
+
export type { UseTableSelectionReturn } from './useTableSelection';
|
|
29
|
+
export { useTableSort } from './useTableSort';
|
|
30
|
+
export type { UseTableSortOptions, UseTableSortReturn } from './useTableSort';
|
|
31
|
+
export { usePlatform } from './usePlatform';
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
extractFilterValue,
|
|
5
|
+
updateFilterCategories,
|
|
6
|
+
} from '../components/FilterMenu/helpers';
|
|
7
|
+
|
|
8
|
+
import type { FilterCategory } from '../components/AppliedFiltersManagerBar/AppliedFiltersManagerBar';
|
|
9
|
+
import type { FilterSchema, FilterValue } from '../components/FilterMenu/types';
|
|
10
|
+
|
|
11
|
+
export interface UseFiltersOptions {
|
|
12
|
+
/** Array of filter schemas defining available filters */
|
|
13
|
+
filterSchemas: FilterSchema[];
|
|
14
|
+
/** Optional initial filter state */
|
|
15
|
+
initialFilters?: FilterCategory[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UseFiltersReturn {
|
|
19
|
+
/** Current filter state */
|
|
20
|
+
filters: FilterCategory[];
|
|
21
|
+
|
|
22
|
+
/** Handler to update filter state */
|
|
23
|
+
onChange: (filters: FilterCategory[]) => void;
|
|
24
|
+
|
|
25
|
+
/** Current filter values keyed by schema key */
|
|
26
|
+
filterValues: Record<string, FilterValue>;
|
|
27
|
+
|
|
28
|
+
/** Update a single filter by key */
|
|
29
|
+
updateFilter: (key: string, value: FilterValue) => void;
|
|
30
|
+
|
|
31
|
+
/** Update multiple filters at once */
|
|
32
|
+
updateFilters: (updates: Record<string, FilterValue>) => void;
|
|
33
|
+
|
|
34
|
+
/** Get current value for a specific filter */
|
|
35
|
+
getFilterValue: (key: string) => FilterValue;
|
|
36
|
+
|
|
37
|
+
/** Get a typed change handler for a specific schema */
|
|
38
|
+
getChangeHandler: (schema: FilterSchema) => (value: FilterValue) => void;
|
|
39
|
+
|
|
40
|
+
/** Clear all filters */
|
|
41
|
+
clearFilters: () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Hook for managing filter state with schema-based filter definitions.
|
|
46
|
+
* Manages filter state internally and provides utilities for updating filters.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* function MyComponent() {
|
|
51
|
+
* const { filters, onChange, clearFilters } = useFilters({
|
|
52
|
+
* filterSchemas: defaultFilterSchemas,
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* return (
|
|
56
|
+
* <>
|
|
57
|
+
* <FilterMenu filters={filters} onFiltersChange={onChange} />
|
|
58
|
+
* <AppliedFiltersManagerBar
|
|
59
|
+
* filterCategories={filters}
|
|
60
|
+
* onClearAll={clearFilters}
|
|
61
|
+
* />
|
|
62
|
+
* </>
|
|
63
|
+
* );
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function useFilters({
|
|
68
|
+
filterSchemas,
|
|
69
|
+
initialFilters = [],
|
|
70
|
+
}: UseFiltersOptions): UseFiltersReturn {
|
|
71
|
+
const [filters, setFilters] = useState<FilterCategory[]>(initialFilters);
|
|
72
|
+
|
|
73
|
+
// Extract filter values from FilterCategory[] structure using schemas
|
|
74
|
+
const filterValues = useMemo(() => {
|
|
75
|
+
const values: Record<string, FilterValue> = {};
|
|
76
|
+
filterSchemas.forEach(schema => {
|
|
77
|
+
values[schema.key] = extractFilterValue(schema, filters);
|
|
78
|
+
});
|
|
79
|
+
return values;
|
|
80
|
+
}, [filterSchemas, filters]);
|
|
81
|
+
|
|
82
|
+
// Handler to update filter state
|
|
83
|
+
const onChange = useCallback((newFilters: FilterCategory[]) => {
|
|
84
|
+
setFilters(newFilters);
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
87
|
+
// Update a single filter by key
|
|
88
|
+
const updateFilter = useCallback(
|
|
89
|
+
(key: string, value: FilterValue) => {
|
|
90
|
+
setFilters(currentFilters => {
|
|
91
|
+
const schema = filterSchemas.find(s => s.key === key);
|
|
92
|
+
if (!schema) return currentFilters;
|
|
93
|
+
|
|
94
|
+
return updateFilterCategories(
|
|
95
|
+
filterSchemas,
|
|
96
|
+
{ [key]: value },
|
|
97
|
+
currentFilters,
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
[filterSchemas],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Update multiple filters at once
|
|
105
|
+
const updateFilters = useCallback(
|
|
106
|
+
(updates: Record<string, FilterValue>) => {
|
|
107
|
+
setFilters(currentFilters => {
|
|
108
|
+
return updateFilterCategories(filterSchemas, updates, currentFilters);
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
[filterSchemas],
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Get current value for a specific filter
|
|
115
|
+
const getFilterValue = useCallback(
|
|
116
|
+
(key: string): FilterValue => {
|
|
117
|
+
return (
|
|
118
|
+
filterValues[key] ??
|
|
119
|
+
(filterSchemas.find(s => s.key === key)?.type === 'boolean'
|
|
120
|
+
? false
|
|
121
|
+
: [])
|
|
122
|
+
);
|
|
123
|
+
},
|
|
124
|
+
[filterValues, filterSchemas],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Get a typed change handler for a specific schema
|
|
128
|
+
const getChangeHandler = useCallback(
|
|
129
|
+
(schema: FilterSchema) => {
|
|
130
|
+
return (value: FilterValue) => {
|
|
131
|
+
updateFilter(schema.key, value);
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
[updateFilter],
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Clear all filters
|
|
138
|
+
const clearFilters = useCallback(() => {
|
|
139
|
+
setFilters([]);
|
|
140
|
+
}, []);
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
filters,
|
|
144
|
+
onChange,
|
|
145
|
+
filterValues,
|
|
146
|
+
updateFilter,
|
|
147
|
+
updateFilters,
|
|
148
|
+
getFilterValue,
|
|
149
|
+
getChangeHandler,
|
|
150
|
+
clearFilters,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useInView } from 'react-intersection-observer';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options for the useInfiniteScroll hook
|
|
7
|
+
*/
|
|
8
|
+
export interface UseInfiniteScrollOptions {
|
|
9
|
+
/** Whether there are more pages to fetch */
|
|
10
|
+
hasNextPage: boolean;
|
|
11
|
+
/** Whether the next page is currently being fetched */
|
|
12
|
+
isFetchingNextPage: boolean;
|
|
13
|
+
/** Function to call to fetch the next page */
|
|
14
|
+
fetchNextPage: () => void;
|
|
15
|
+
/** Threshold at which to trigger the intersection observer (default: 0) */
|
|
16
|
+
threshold?: number;
|
|
17
|
+
/** Root margin for the intersection observer (default: '100px') */
|
|
18
|
+
rootMargin?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Custom hook for implementing infinite scroll with automatic fetching
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
|
27
|
+
* useInfiniteQuery(queryOptions);
|
|
28
|
+
*
|
|
29
|
+
* const { ref } = useInfiniteScroll({
|
|
30
|
+
* hasNextPage,
|
|
31
|
+
* isFetchingNextPage,
|
|
32
|
+
* fetchNextPage,
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* return (
|
|
36
|
+
* <>
|
|
37
|
+
* {items.map(item => <Item key={item.id} {...item} />)}
|
|
38
|
+
* <div ref={ref} />
|
|
39
|
+
* </>
|
|
40
|
+
* );
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function useInfiniteScroll({
|
|
44
|
+
hasNextPage,
|
|
45
|
+
isFetchingNextPage,
|
|
46
|
+
fetchNextPage,
|
|
47
|
+
threshold = 0,
|
|
48
|
+
rootMargin = '100px',
|
|
49
|
+
}: UseInfiniteScrollOptions) {
|
|
50
|
+
const { ref, inView } = useInView({
|
|
51
|
+
threshold,
|
|
52
|
+
rootMargin,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (inView && hasNextPage && !isFetchingNextPage) {
|
|
57
|
+
fetchNextPage();
|
|
58
|
+
}
|
|
59
|
+
}, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);
|
|
60
|
+
|
|
61
|
+
return { ref, inView };
|
|
62
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
type PlatformInfo = {
|
|
4
|
+
isMac: boolean;
|
|
5
|
+
submitModifierLabel: '⌘' | 'Ctrl';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function detectIsMac(): boolean {
|
|
9
|
+
if (typeof navigator === 'undefined') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const navigatorWithUserAgentData = navigator as Navigator & {
|
|
14
|
+
userAgentData?: { platform?: string };
|
|
15
|
+
};
|
|
16
|
+
const userAgentDataPlatform =
|
|
17
|
+
navigatorWithUserAgentData.userAgentData?.platform;
|
|
18
|
+
const platform =
|
|
19
|
+
userAgentDataPlatform ?? navigator.platform ?? navigator.userAgent;
|
|
20
|
+
|
|
21
|
+
return /mac|iphone|ipad|ipod/i.test(platform);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function usePlatform(): PlatformInfo {
|
|
25
|
+
return useMemo(() => {
|
|
26
|
+
const isMac = detectIsMac();
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
isMac,
|
|
30
|
+
submitModifierLabel: isMac ? '⌘' : 'Ctrl',
|
|
31
|
+
};
|
|
32
|
+
}, []);
|
|
33
|
+
}
|