8.6 מנטין מתקדם הרצאה
מנטין מתקדם - Advanced Mantine¶
בשיעור זה נלמד טכניקות מתקדמות של Mantine: יצירת theme מותאם, שימוש ב-Styles API, משתני CSS, סגנונות רספונסיביים, קומפוננטות פולימורפיות, ובניית קומפוננטה מותאמת עם factory.
יצירת Theme מותאם עם createTheme¶
הגדרה מלאה של theme¶
import { createTheme, MantineColorsTuple, MantineProvider } from "@mantine/core";
const brand: MantineColorsTuple = [
"#f0f4ff",
"#dce4f5",
"#b4c6e7",
"#8aa7db",
"#668dd0",
"#4e7dc9",
"#4275c7",
"#3363b0",
"#29589e",
"#1a4b8c",
];
const theme = createTheme({
// צבעים
colors: {
brand,
},
primaryColor: "brand",
primaryShade: { light: 6, dark: 8 },
// פונטים
fontFamily: "Rubik, sans-serif",
fontFamilyMonospace: "JetBrains Mono, monospace",
headings: {
fontFamily: "Heebo, sans-serif",
fontWeight: "700",
sizes: {
h1: { fontSize: "2.5rem", lineHeight: "1.2" },
h2: { fontSize: "2rem", lineHeight: "1.3" },
h3: { fontSize: "1.5rem", lineHeight: "1.4" },
},
},
// גדלים
fontSizes: {
xs: "0.75rem",
sm: "0.875rem",
md: "1rem",
lg: "1.125rem",
xl: "1.25rem",
},
spacing: {
xs: "0.5rem",
sm: "0.75rem",
md: "1rem",
lg: "1.5rem",
xl: "2rem",
},
radius: {
xs: "2px",
sm: "4px",
md: "8px",
lg: "16px",
xl: "32px",
},
// ברירות מחדל
defaultRadius: "md",
cursorType: "pointer",
// breakpoints
breakpoints: {
xs: "36em",
sm: "48em",
md: "62em",
lg: "75em",
xl: "88em",
},
// דריסת ברירות מחדל של קומפוננטות
components: {
Button: {
defaultProps: {
radius: "md",
},
},
TextInput: {
defaultProps: {
radius: "md",
},
},
Paper: {
defaultProps: {
radius: "md",
shadow: "sm",
},
},
Card: {
defaultProps: {
radius: "md",
shadow: "sm",
withBorder: true,
},
},
},
});
function App() {
return (
<MantineProvider theme={theme}>
{/* כל הקומפוננטות ישתמשו ב-theme הזה */}
</MantineProvider>
);
}
- primaryShade מאפשר הגדרת גוון שונה למצב בהיר וכהה
- components מאפשר הגדרת ברירות מחדל לכל קומפוננטה
- כל ערכי ה-theme זמינים דרך משתני CSS
גישה ל-theme בקומפוננטות¶
import { useMantineTheme } from "@mantine/core";
function ThemeAwareComponent() {
const theme = useMantineTheme();
return (
<div style={{ color: theme.colors.brand[6] }}>
צבע מהתימה
</div>
);
}
Styles API - שליטה על סגנונות¶
כל קומפוננטה של Mantine מורכבת מחלקים פנימיים שניתן לעצב בנפרד.
classNames - הוספת מחלקות CSS¶
/* CustomButton.module.css */
.root {
font-weight: 600;
letter-spacing: 0.5px;
}
.label {
text-transform: uppercase;
}
.inner {
gap: 8px;
}
import { Button } from "@mantine/core";
import styles from "./CustomButton.module.css";
function CustomButton() {
return (
<Button
classNames={{
root: styles.root,
label: styles.label,
inner: styles.inner,
}}
>
כפתור מותאם
</Button>
);
}
styles prop - סגנונות אינליין לכל חלק¶
import { TextInput } from "@mantine/core";
function CustomInput() {
return (
<TextInput
label="שם"
styles={{
root: { marginBottom: 16 },
label: { fontWeight: 700, fontSize: 14, color: "#333" },
input: {
borderColor: "#4275c7",
"&:focus": { borderColor: "#1a4b8c" },
},
error: { fontSize: 12, marginTop: 4 },
}}
/>
);
}
הגדרת סגנונות ברמת ה-theme¶
const theme = createTheme({
components: {
Button: {
classNames: {
root: "my-button-root",
label: "my-button-label",
},
styles: {
root: { fontWeight: 600 },
},
},
TextInput: {
styles: (theme) => ({
label: {
fontWeight: 600,
marginBottom: 4,
},
input: {
borderRadius: theme.radius.md,
},
}),
},
Card: {
defaultProps: {
shadow: "sm",
radius: "md",
withBorder: true,
},
styles: {
root: {
transition: "box-shadow 0.2s ease",
"&:hover": {
boxShadow: "var(--mantine-shadow-md)",
},
},
},
},
},
});
משתני CSS ו-Theme Tokens¶
Mantine מייצרת משתני CSS אוטומטית מה-theme:
משתנים זמינים¶
/* צבעים */
var(--mantine-color-blue-5)
var(--mantine-color-brand-6)
var(--mantine-primary-color-filled)
var(--mantine-primary-color-light)
/* פונטים */
var(--mantine-font-family)
var(--mantine-font-family-monospace)
var(--mantine-font-size-md)
/* ריווח */
var(--mantine-spacing-md)
var(--mantine-spacing-lg)
/* רדיוס */
var(--mantine-radius-md)
var(--mantine-radius-lg)
/* צל */
var(--mantine-shadow-sm)
var(--mantine-shadow-md)
/* Breakpoints */
var(--mantine-breakpoint-sm)
var(--mantine-breakpoint-md)
/* מצב בהיר/כהה */
var(--mantine-color-scheme)
שימוש ב-CSS Modules עם משתני Mantine¶
/* Dashboard.module.css */
.card {
padding: var(--mantine-spacing-lg);
border-radius: var(--mantine-radius-md);
background-color: var(--mantine-color-body);
border: 1px solid var(--mantine-color-default-border);
transition: box-shadow 0.2s ease;
}
.card:hover {
box-shadow: var(--mantine-shadow-md);
}
.title {
font-family: var(--mantine-font-family-headings);
font-size: var(--mantine-font-size-lg);
font-weight: 700;
color: var(--mantine-color-text);
}
.description {
font-size: var(--mantine-font-size-sm);
color: var(--mantine-color-dimmed);
line-height: 1.6;
}
/* שימוש במצב כהה */
.highlight {
background-color: var(--mantine-color-blue-0);
}
[data-mantine-color-scheme="dark"] .highlight {
background-color: var(--mantine-color-blue-9);
}
הוספת משתני CSS מותאמים¶
import { createTheme, CSSVariablesResolver } from "@mantine/core";
const resolver: CSSVariablesResolver = (theme) => ({
variables: {
"--sidebar-width": "250px",
"--header-height": "60px",
"--content-max-width": "1200px",
},
light: {
"--app-bg": theme.colors.gray[0],
"--card-bg": theme.white,
"--text-primary": theme.colors.gray[9],
},
dark: {
"--app-bg": theme.colors.dark[7],
"--card-bg": theme.colors.dark[6],
"--text-primary": theme.colors.gray[0],
},
});
function App() {
return (
<MantineProvider theme={theme} cssVariablesResolver={resolver}>
{/* כעת ניתן להשתמש ב-var(--sidebar-width) בכל מקום */}
</MantineProvider>
);
}
סגנונות רספונסיביים עם Mantine¶
System Props רספונסיביים¶
import { SimpleGrid, Text, Paper, Box } from "@mantine/core";
function ResponsiveExample() {
return (
<>
{/* רשת רספונסיבית */}
<SimpleGrid
cols={{ base: 1, sm: 2, lg: 3 }}
spacing={{ base: "sm", sm: "md", lg: "lg" }}
>
<Paper p="md" shadow="xs">1</Paper>
<Paper p="md" shadow="xs">2</Paper>
<Paper p="md" shadow="xs">3</Paper>
</SimpleGrid>
{/* גלוי/נסתר */}
<Box visibleFrom="md">
<Text>נראה רק בדסקטופ</Text>
</Box>
<Box hiddenFrom="md">
<Text>נראה רק בטלפון/טאבלט</Text>
</Box>
{/* Flex רספונסיבי */}
<Flex
direction={{ base: "column", sm: "row" }}
gap={{ base: "sm", sm: "lg" }}
>
<Button>1</Button>
<Button>2</Button>
</Flex>
</>
);
}
שימוש ב-media queries עם CSS Modules של Mantine¶
/* Responsive.module.css */
.container {
padding: var(--mantine-spacing-sm);
}
@media (min-width: 48em) {
.container {
padding: var(--mantine-spacing-lg);
}
}
/* שימוש ב-mixin של postcss-preset-mantine */
.sidebar {
display: none;
@media (min-width: 48em) {
display: block;
width: 250px;
}
}
קומפוננטות פולימורפיות - Polymorphic Components¶
קומפוננטות פולימורפיות יכולות לשנות את אלמנט ה-HTML שהן מרנדרות:
import { Button, Text, Paper, Group } from "@mantine/core";
function PolymorphicExamples() {
return (
<>
{/* Button כ-anchor */}
<Button component="a" href="https://example.com" target="_blank">
קישור שנראה ככפתור
</Button>
{/* Text כ-label */}
<Text component="label" htmlFor="my-input" fw={500}>
תווית
</Text>
{/* Paper כ-article */}
<Paper component="article" p="md" shadow="xs">
מאמר
</Paper>
{/* Button עם React Router Link */}
{/* <Button component={Link} to="/dashboard">ניווט</Button> */}
{/* Text כ-span */}
<Text span c="blue" fw={700}>
טקסט מודגש בתוך שורה
</Text>
</>
);
}
- component prop משנה את אלמנט ה-HTML הבסיסי
- כל ה-props של האלמנט החדש זמינים (href ל-a, to ל-Link)
- TypeScript יבדוק שה-props תואמים לאלמנט
דוגמה עם TypeScript מלא¶
import { Button, ButtonProps } from "@mantine/core";
import { Link, LinkProps } from "react-router-dom";
// כפתור ניווט שמשלב Button עם Link
type NavButtonProps = ButtonProps & LinkProps;
function NavButton(props: NavButtonProps) {
return <Button component={Link} {...props} />;
}
// שימוש
function Nav() {
return (
<Group>
<NavButton to="/" variant="subtle">בית</NavButton>
<NavButton to="/about" variant="subtle">אודות</NavButton>
</Group>
);
}
בניית קומפוננטה מותאמת עם Factory¶
Mantine מאפשרת ליצור קומפוננטות מותאמות שתומכות ב-Styles API, theme overrides, ו-ref forwarding.
דוגמה בסיסית¶
import {
Box,
BoxProps,
StylesApiProps,
factory,
Factory,
useProps,
useStyles,
} from "@mantine/core";
import classes from "./StatCard.module.css";
// הגדרת הטיפוסים
export type StatCardStylesNames = "root" | "title" | "value" | "description";
export interface StatCardProps
extends BoxProps,
StylesApiProps<StatCardFactory> {
title: string;
value: string | number;
description?: string;
}
type StatCardFactory = Factory<{
props: StatCardProps;
ref: HTMLDivElement;
stylesNames: StatCardStylesNames;
}>;
// ברירות מחדל
const defaultProps: Partial<StatCardProps> = {};
// הקומפוננטה
const StatCard = factory<StatCardFactory>((_props, ref) => {
const props = useProps("StatCard", defaultProps, _props);
const { title, value, description, classNames, styles, className, style, ...others } = props;
const getStyles = useStyles<StatCardFactory>({
name: "StatCard",
classes,
props,
classNames,
styles,
className,
style,
});
return (
<Box ref={ref} {...getStyles("root")} {...others}>
<div {...getStyles("title")}>{title}</div>
<div {...getStyles("value")}>{value}</div>
{description && <div {...getStyles("description")}>{description}</div>}
</Box>
);
});
StatCard.displayName = "StatCard";
StatCard.classes = classes;
export { StatCard };
/* StatCard.module.css */
.root {
padding: var(--mantine-spacing-lg);
border-radius: var(--mantine-radius-md);
background-color: var(--mantine-color-body);
border: 1px solid var(--mantine-color-default-border);
}
.title {
font-size: var(--mantine-font-size-sm);
color: var(--mantine-color-dimmed);
margin-bottom: var(--mantine-spacing-xs);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.value {
font-size: 2rem;
font-weight: 700;
color: var(--mantine-color-text);
line-height: 1;
}
.description {
font-size: var(--mantine-font-size-sm);
color: var(--mantine-color-dimmed);
margin-top: var(--mantine-spacing-xs);
}
שימוש בקומפוננטה¶
import { StatCard } from "./StatCard";
function Dashboard() {
return (
<SimpleGrid cols={4}>
<StatCard title="משתמשים" value="1,234" description="+12% מהחודש שעבר" />
<StatCard title="הזמנות" value="567" description="+8%" />
<StatCard title="הכנסות" value="45K" />
<StatCard
title="המרות"
value="4.8%"
styles={{
value: { color: "var(--mantine-color-green-6)" },
}}
/>
</SimpleGrid>
);
}
- הקומפוננטה תומכת ב-classNames, styles, system props
- ניתן לדרוס סגנונות ברמת ה-theme
- ref forwarding עובד כמו בכל קומפוננטה של Mantine
דריסת סגנונות ב-theme¶
const theme = createTheme({
components: {
StatCard: {
classNames: {
root: "my-stat-card",
},
styles: {
value: { color: "var(--mantine-primary-color-filled)" },
},
},
},
});
דפוסים מתקדמים¶
ירושת Theme בקומפוננטות מקוננות¶
import { MantineProvider, createTheme, Button, Stack } from "@mantine/core";
const sectionTheme = createTheme({
primaryColor: "red",
defaultRadius: "xl",
});
function SpecialSection() {
return (
<MantineProvider theme={sectionTheme}>
<Stack>
<Button>כפתור אדום עם פינות מעוגלות</Button>
<Button variant="outline">מתאר אדום</Button>
</Stack>
</MantineProvider>
);
}
function App() {
return (
<MantineProvider>
<Stack>
<Button>כפתור כחול רגיל</Button>
<SpecialSection />
<Button>עדיין כחול</Button>
</Stack>
</MantineProvider>
);
}
- MantineProvider מקונן דורס את ה-theme רק לילדים שלו
- שימושי לאזורים עם עיצוב שונה באותו דף
שימוש ב-data attributes¶
import { Button, ButtonProps } from "@mantine/core";
interface StatusButtonProps extends ButtonProps {
status: "active" | "pending" | "error";
}
function StatusButton({ status, ...others }: StatusButtonProps) {
return <Button data-status={status} {...others} />;
}
/* סגנונות מבוססי data attributes */
.mantine-Button-root[data-status="active"] {
--button-bg: var(--mantine-color-green-6);
}
.mantine-Button-root[data-status="pending"] {
--button-bg: var(--mantine-color-yellow-6);
}
.mantine-Button-root[data-status="error"] {
--button-bg: var(--mantine-color-red-6);
}
סיכום¶
- createTheme מאפשר התאמה אישית מלאה של צבעים, פונטים, גדלים ורדיוסים
- ניתן להגדיר ברירות מחדל לכל קומפוננטה דרך components ב-theme
- Styles API מאפשר גישה לכל חלק פנימי של קומפוננטה דרך classNames ו-styles
- משתני CSS של Mantine זמינים בכל הפרויקט ומאפשרים עקביות
- CSSVariablesResolver מאפשר הוספת משתנים מותאמים עם תמיכה במצב כהה
- קומפוננטות פולימורפיות משנות את אלמנט ה-HTML עם component prop
- factory מאפשר ליצור קומפוננטות מותאמות עם תמיכה מלאה ב-Styles API
- MantineProvider מקונן מאפשר theme שונה לאזורים ספציפיים