Make twenty-ui theming a consumer-facing API (#22007)
**What** - Add `useTheme()` and `useThemeColorScheme()` as the public theme accessors, and migrate the 88 internal `useContext(ThemeContext)` call sites to them. `ThemeContext` stays exported. - Make `ThemeProvider` overridable and scopeable: new `applyToRoot` (default `true`), `overrides` (a `--t-*` map), and `className` props. When scoping is requested it renders a `display: contents` wrapper that also serves as the themed portal container, exposed via `ThemeScopeContext` / `useThemeContainer()`. `AppTooltip` and `Modal` portal into that container, falling back to `document.body`. - Document the `--t-*` override contract in the README; barrels regenerated. **Why** Consumers had no stable theme accessor (they reached into the raw context) and no supported way to re-theme. This adds both without behavior change. **Reviewer notes** - The default path is unchanged: `applyToRoot` defaults to `true`, so the colorScheme class still lands on `<html>` and portaled overlays (tooltips, dropdowns, modals) stay themed. The global class is load-bearing for body portals; scoping is opt-in. - `twenty-front` is untouched (migrating its consumers is a separate follow-up). <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22007?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -122,6 +122,30 @@ diff cleanly against their sources).
|
||||
- Tokens live in `src/theme/` (`THEME_LIGHT` / `THEME_DARK`); the `--t-*` CSS variables and the `themeCssVariables` accessor are static files mirrored token-for-token from `twenty-ui-deprecated` (matching its own static-CSS approach).
|
||||
- A theme parity test asserts the theme CSS and `themeCssVariables` stay identical to `twenty-ui-deprecated`'s `--t-*` values.
|
||||
|
||||
### Consuming the theme
|
||||
|
||||
- Wrap the app once in `ThemeProvider` and import `twenty-ui/theme-light.css` and `twenty-ui/theme-dark.css`.
|
||||
- Read theme values with the public hooks, not the raw context:
|
||||
- `useTheme()` returns the resolved `ThemeType` (numeric tokens such as `theme.icon.size.sm`). Outside a provider it yields the default light theme.
|
||||
- `useThemeColorScheme()` returns the active `'light' | 'dark'`.
|
||||
- Colors are consumed as `var(--t-*)` strings via `themeCssVariables` (the browser resolves them against the in-scope `--t-*`), so overriding the variables re-themes color automatically.
|
||||
|
||||
### Customizing the theme (`--t-*` override contract)
|
||||
|
||||
The supported way to re-theme is to override the `--t-*` CSS variables. Their names are exactly the keys declared in `theme-light.css` / `theme-dark.css`. Two mechanisms:
|
||||
|
||||
1. **Globally** — ship a stylesheet that redefines `--t-*` under `.light` / `.dark`. This covers the whole document, including overlays portaled to `document.body`.
|
||||
2. **Per `ThemeProvider`** — pass `overrides` (a `ThemeOverrides` map of `--t-*` name to value). The variables are applied to the provider's subtree.
|
||||
|
||||
`ThemeProvider` props:
|
||||
|
||||
- `colorScheme: 'light' | 'dark'` — required.
|
||||
- `applyToRoot?: boolean` (default `true`) — toggles the `.light` / `.dark` class on `document.documentElement`. Keep it `true` so the whole document, including portaled overlays (tooltips, dropdowns, modals) rendered to `document.body`, stays themed. Set it `false` when the host manages its own color-scheme class or when mounting more than one provider, so the providers don't clobber the root.
|
||||
- `overrides?: ThemeOverrides` — `--t-*` variable overrides scoped to this provider's subtree.
|
||||
- `className?: string` — extra class on the scoped wrapper.
|
||||
|
||||
**Scoped theming and portals.** When `applyToRoot` is `false` or `overrides` is set, the provider scopes the variables to a wrapper element. Overlays portal to `document.body` (outside that wrapper), so for them to inherit the scoped variables the provider also exposes a themed portal container via `ThemeScopeContext`; read it with `useThemeContainer()` and pass it as the overlay's portal container. The library's `AppTooltip` and `Modal` already do this, falling back to `document.body` when no scoped provider is present (the default global path is unchanged).
|
||||
|
||||
## Component migration map
|
||||
|
||||
Components split into two buckets. *(The migration is complete; see
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { useContext } from 'react';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
export type AnimatedCheckmarkProps = React.ComponentProps<
|
||||
typeof motion.path
|
||||
@@ -17,7 +16,7 @@ export const AnimatedCheckmark = ({
|
||||
duration = 0.5,
|
||||
size = 28,
|
||||
}: AnimatedCheckmarkProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<svg
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { isNonEmptyString, isNull, isUndefined } from '@sniptt/guards';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { handleClickableElementKeyDown } from '@ui/accessibility/utils/handleClickableElementKeyDown';
|
||||
import { type AvatarSize } from '@ui/data-display/Avatar/types/AvatarSize';
|
||||
import { type AvatarType } from '@ui/data-display/Avatar/types/AvatarType';
|
||||
import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { stringToThemeColorP3String } from '@ui/utilities';
|
||||
import { type Nullable } from '@ui/utilities/types/Nullable';
|
||||
|
||||
@@ -41,7 +41,7 @@ export const Avatar = ({
|
||||
backgroundColor,
|
||||
borderColor,
|
||||
}: AvatarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const [erroredAvatarImageURI, setErroredAvatarImageURI] = useState<
|
||||
string | null
|
||||
|
||||
@@ -4,9 +4,8 @@ import { handleClickableElementKeyDown } from '@ui/accessibility/utils/handleCli
|
||||
import { Avatar } from '@ui/data-display/Avatar/Avatar';
|
||||
import { type AvatarType } from '@ui/data-display/Avatar/types/AvatarType';
|
||||
import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { type Nullable } from '@ui/utilities';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import styles from './AvatarOrIcon.module.scss';
|
||||
@@ -34,7 +33,7 @@ export const AvatarOrIcon = ({
|
||||
IconBackgroundColor,
|
||||
onClick,
|
||||
}: AvatarOrIconProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
if (!isDefined(Icon)) {
|
||||
return (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { clsx } from 'clsx';
|
||||
|
||||
import { IconCheck } from '@ui/icon/components/TablerIcons';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './Checkmark.module.scss';
|
||||
|
||||
@@ -12,7 +12,7 @@ export type CheckmarkProps = React.ComponentPropsWithoutRef<'div'> & {
|
||||
};
|
||||
|
||||
export const Checkmark = ({ className }: CheckmarkProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div className={clsx(styles.root, className)}>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { OverflowingTextWithTooltip } from '@ui/surfaces/OverflowingTextWithTooltip/OverflowingTextWithTooltip';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext, themeCssVariables } from '@ui/theme-constants';
|
||||
import { themeCssVariables, useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import styles from './Tag.module.scss';
|
||||
@@ -35,7 +34,7 @@ export const Tag = ({
|
||||
preventShrink,
|
||||
preventPadding,
|
||||
}: TagProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const tagBackground =
|
||||
color === 'transparent'
|
||||
|
||||
@@ -2,8 +2,7 @@ import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { StyledTintedIconTileContainer } from '@ui/data-display/StyledTintedIconTileContainer/StyledTintedIconTileContainer';
|
||||
import { getIconTileColorShades } from '@ui/data-display/TintedIconTile/utils/getIconTileColorShades';
|
||||
import { DEFAULT_THEME_COLOR_FALLBACK } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
export type TintedIconTileProps = {
|
||||
@@ -19,7 +18,7 @@ export const TintedIconTile = ({
|
||||
size: sizeFromProps,
|
||||
stroke: strokeFromProps,
|
||||
}: TintedIconTileProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const style = getIconTileColorShades(color);
|
||||
const iconSize = sizeFromProps ?? theme.icon.size.md;
|
||||
const iconStroke = strokeFromProps ?? theme.icon.stroke.md;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { animate, motion, useMotionValue, useTransform } from 'framer-motion';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { BACKGROUND } from '@ui/feedback/AnimatedPlaceholder/constants/Background';
|
||||
import { DARK_BACKGROUND } from '@ui/feedback/AnimatedPlaceholder/constants/DarkBackground';
|
||||
import { DARK_MOVING_IMAGE } from '@ui/feedback/AnimatedPlaceholder/constants/DarkMovingImage';
|
||||
import { MOVING_IMAGE } from '@ui/feedback/AnimatedPlaceholder/constants/MovingImage';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useThemeColorScheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './AnimatedPlaceholder.module.scss';
|
||||
|
||||
@@ -22,7 +22,7 @@ type AnimatedPlaceholderProps = {
|
||||
};
|
||||
|
||||
export const AnimatedPlaceholder = ({ type }: AnimatedPlaceholderProps) => {
|
||||
const { colorScheme } = useContext(ThemeContext);
|
||||
const colorScheme = useThemeColorScheme();
|
||||
|
||||
const x = useMotionValue(window.innerWidth / 2);
|
||||
const y = useMotionValue(window.innerHeight / 2);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { IconInfoCircle } from '@ui/icon/components/TablerIcons';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import { Button } from '@ui/input/Button/Button';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import styles from './Info.module.scss';
|
||||
@@ -29,7 +29,7 @@ export const Info = ({
|
||||
onClick,
|
||||
to,
|
||||
}: InfoProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div className={clsx(styles.info, INFO_ACCENT_CLASS_NAMES[accent])}>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { Button } from '@ui/input/Button/Button';
|
||||
import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { IconInfoCircle } from '@ui/icon/components/TablerIcons';
|
||||
@@ -27,7 +26,7 @@ export const InlineBanner = ({
|
||||
LeftIcon = IconInfoCircle,
|
||||
className,
|
||||
}: InlineBannerProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Banner
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconAddressBookRaw from '@assets/icons/address-book.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconAddressBookProps = Pick<
|
||||
IconComponentProps,
|
||||
@@ -10,7 +8,7 @@ type IconAddressBookProps = Pick<
|
||||
>;
|
||||
|
||||
export const IconAddressBook = (props: IconAddressBookProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? 24;
|
||||
const stroke = props.stroke ?? theme.icon.stroke.md;
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconAnthropicRaw from '@assets/icons/anthropic.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconBrandAnthropicProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconBrandAnthropic = (props: IconBrandAnthropicProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconAnthropicRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconBrandGeminiRaw from '@assets/icons/gemini.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconBrandGeminiProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconBrandGemini = (props: IconBrandGeminiProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconBrandGeminiRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconBrandGroqRaw from '@assets/icons/groq.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconBrandGroqProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconBrandGroq = (props: IconBrandGroqProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconBrandGroqRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconBrandMistralRaw from '@assets/icons/mistral.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconBrandMistralProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconBrandMistral = (props: IconBrandMistralProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconBrandMistralRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconBrandXaiRaw from '@assets/icons/xai.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconBrandXaiProps = Pick<IconComponentProps, 'size' | 'color'>;
|
||||
|
||||
export const IconBrandXai = (props: IconBrandXaiProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { IconChartBar } from '@ui/icon/components/TablerIcons';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './IconChartBarHorizontal.module.scss';
|
||||
|
||||
@@ -12,7 +10,7 @@ type IconChartBarHorizontalProps = Pick<
|
||||
>;
|
||||
|
||||
export const IconChartBarHorizontal = (props: IconChartBarHorizontalProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.md;
|
||||
const stroke = props.stroke ?? theme.icon.stroke.sm;
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconGmailRaw from '@assets/icons/gmail.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconGmailProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconGmail = (props: IconGmailProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconGmailRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconGoogleRaw from '@assets/icons/google.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconGoogleProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconGoogle = (props: IconGoogleProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconGoogleRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconGoogleCalendarRaw from '@assets/icons/google-calendar.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconGoogleCalendarProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconGoogleCalendar = (props: IconGoogleCalendarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconGoogleCalendarRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconLockRaw from '@assets/icons/lock.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconLockCustomProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconLockCustom = (props: IconLockCustomProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconLockRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconMicrosoftRaw from '@assets/icons/microsoft.svg?react';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
interface IconMicrosoftProps {
|
||||
size?: number | string;
|
||||
}
|
||||
|
||||
export const IconMicrosoft = (props: IconMicrosoftProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconMicrosoftRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconMicrosoftCalendarRaw from '@assets/icons/microsoft-calendar.svg?react';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
interface IconMicrosoftCalendarProps {
|
||||
size?: number | string;
|
||||
}
|
||||
|
||||
export const IconMicrosoftCalendar = (props: IconMicrosoftCalendarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconMicrosoftCalendarRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconMicrosoftOutlookRaw from '@assets/icons/microsoft-outlook.svg?react';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
interface IconMicrosoftOutlookProps {
|
||||
size?: number | string;
|
||||
}
|
||||
|
||||
export const IconMicrosoftOutlook = (props: IconMicrosoftOutlookProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconMicrosoftOutlookRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconModelClaudeRaw from '@assets/icons/claude.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconModelClaudeProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IconModelClaude = (props: IconModelClaudeProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return <IconModelClaudeRaw height={size} width={size} />;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconOpenaiRaw from '@assets/icons/openai.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconProviderOpenaiProps = Pick<IconComponentProps, 'size' | 'color'>;
|
||||
|
||||
export const IconProviderOpenai = (props: IconProviderOpenaiProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconRelationManyToOneRaw from '@assets/icons/many-to-one.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconRelationManyToOneProps = Pick<IconComponentProps, 'size' | 'stroke'>;
|
||||
|
||||
export const IconRelationManyToOne = (props: IconRelationManyToOneProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? 24;
|
||||
const stroke = props.stroke ?? theme.icon.stroke.md;
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconTrashXOffRaw from '@assets/icons/trash-x-off.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconTrashXOffProps = Pick<IconComponentProps, 'size' | 'stroke'>;
|
||||
|
||||
export const IconTrashXOff = (props: IconTrashXOffProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
const stroke = props.stroke ?? theme.icon.stroke.md;
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconTwentyStarRaw from '@assets/icons/twenty-star.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconTwentyStarProps = Pick<IconComponentProps, 'size' | 'stroke'>;
|
||||
|
||||
export const IconTwentyStar = (props: IconTwentyStarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? 24;
|
||||
const stroke = props.stroke ?? theme.icon.stroke.md;
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IconTwentyStarFilledRaw from '@assets/icons/twenty-star-filled.svg?react';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IconTwentyStarFilledProps = Pick<IconComponentProps, 'size' | 'stroke'>;
|
||||
|
||||
export const IconTwentyStarFilled = (props: IconTwentyStarFilledProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? 24;
|
||||
const stroke = props.stroke ?? theme.icon.stroke.md;
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconArrayRaw from '@assets/icons/illustration-array.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconArrayProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconArray = (props: IllustrationIconArrayProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconCalendarEventRaw from '@assets/icons/illustration-calendar-event.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconCalendarEventProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconCalendarEvent = (
|
||||
props: IllustrationIconCalendarEventProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconCalendarTimeRaw from '@assets/icons/illustration-calendar-time.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconCalendarTimeProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconCalendarTime = (
|
||||
props: IllustrationIconCalendarTimeProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconCurrencyRaw from '@assets/icons/illustration-currency.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconCurrencyProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconCurrency = (
|
||||
props: IllustrationIconCurrencyProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconFileRaw from '@assets/icons/illustration-file.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconFileProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconFile = (props: IllustrationIconFileProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconJsonRaw from '@assets/icons/illustration-json.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconJsonProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconJson = (props: IllustrationIconJsonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconLinkRaw from '@assets/icons/illustration-link.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconLinkProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconLink = (props: IllustrationIconLinkProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconMailRaw from '@assets/icons/illustration-mail.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconMailProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconMail = (props: IllustrationIconMailProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconManyToManyRaw from '@assets/icons/illustration-many-to-many.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconManyToManyProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconManyToMany = (
|
||||
props: IllustrationIconManyToManyProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconMapRaw from '@assets/icons/illustration-map.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconMapProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconMap = (props: IllustrationIconMapProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconNumbersRaw from '@assets/icons/illustration-numbers.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconNumbersProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconNumbers = (
|
||||
props: IllustrationIconNumbersProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconOneToManyRaw from '@assets/icons/illustration-one-to-many.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconOneToManyProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconOneToMany = (
|
||||
props: IllustrationIconOneToManyProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconOneToOneRaw from '@assets/icons/illustration-one-to-one.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconOneToOneProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconOneToOne = (
|
||||
props: IllustrationIconOneToOneProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconPhoneRaw from '@assets/icons/illustration-phone.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconPhoneProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconPhone = (props: IllustrationIconPhoneProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconSettingRaw from '@assets/icons/illustration-setting.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconSettingProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconSetting = (
|
||||
props: IllustrationIconSettingProps,
|
||||
) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconStarRaw from '@assets/icons/illustration-star.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconStarProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconStar = (props: IllustrationIconStarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconTagRaw from '@assets/icons/illustration-tag.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconTagProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconTag = (props: IllustrationIconTagProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconTagsRaw from '@assets/icons/illustration-tags.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconTagsProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconTags = (props: IllustrationIconTagsProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconTextRaw from '@assets/icons/illustration-text.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconTextProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconText = (props: IllustrationIconTextProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconToggleRaw from '@assets/icons/illustration-toggle.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconToggleProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconToggle = (props: IllustrationIconToggleProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconUidRaw from '@assets/icons/illustration-uid.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconUidProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconUid = (props: IllustrationIconUidProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import IllustrationIconUserRaw from '@assets/icons/illustration-user.svg?react';
|
||||
import { IllustrationIconWrapper } from '@ui/icon/components/IllustrationIconWrapper';
|
||||
import { type IconComponentProps } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type IllustrationIconUserProps = Pick<IconComponentProps, 'size'>;
|
||||
|
||||
export const IllustrationIconUser = (props: IllustrationIconUserProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const size = props.size ?? theme.icon.size.lg;
|
||||
return (
|
||||
<IllustrationIconWrapper>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Toggle } from '@ui/input';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext, useId } from 'react';
|
||||
import { useId } from 'react';
|
||||
|
||||
import styles from './AdvancedSettingsToggle.module.scss';
|
||||
|
||||
@@ -18,7 +18,7 @@ export const AdvancedSettingsToggle = ({
|
||||
label = 'Advanced',
|
||||
className,
|
||||
}: AdvancedSettingsToggleProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const onChange = (newValue: boolean) => {
|
||||
setIsAdvancedModeEnabled(newValue);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { type MotionProps, motion } from 'framer-motion';
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Pill } from '@ui/data-display/Pill/Pill';
|
||||
import { ThemeContext, themeCssVariables } from '@ui/theme-constants';
|
||||
import { themeCssVariables, useTheme } from '@ui/theme-constants';
|
||||
import { GRAY_SCALE_LIGHT } from '@ui/theme/constants/GrayScaleLight';
|
||||
import { useIsMobile } from '@ui/utilities';
|
||||
import { getOsShortcutSeparator } from '@ui/utilities/device/getOsShortcutSeparator';
|
||||
@@ -335,7 +335,7 @@ export const AnimatedButton = ({
|
||||
dataGloballyPreventClickOutside,
|
||||
soonLabel = 'Soon',
|
||||
}: AnimatedButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
const isDisabled = soon || disabled;
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { motion, type MotionProps } from 'framer-motion';
|
||||
import { type ComponentProps, type MouseEvent, useContext } from 'react';
|
||||
import { type ComponentProps, type MouseEvent } from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import {
|
||||
type LightIconButtonAccent,
|
||||
type LightIconButtonSize,
|
||||
} from '@ui/input/LightIconButton/LightIconButton';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './AnimatedLightIconButton.module.scss';
|
||||
|
||||
@@ -40,7 +40,7 @@ export const AnimatedLightIconButton = ({
|
||||
onClick,
|
||||
title,
|
||||
}: AnimatedLightIconButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { Loader } from '@ui/feedback';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './ButtonIcon.module.scss';
|
||||
|
||||
@@ -12,7 +11,7 @@ export const ButtonIcon = ({
|
||||
Icon?: IconComponent;
|
||||
isLoading?: boolean;
|
||||
}) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div className={styles.iconWrapper}>
|
||||
|
||||
@@ -4,9 +4,13 @@ import { BASE_CODE_EDITOR_THEME_ID } from '@ui/input/CodeEditor/constants/BaseCo
|
||||
import { getBaseCodeEditorTheme } from '@ui/input/CodeEditor/utils/getBaseCodeEditorTheme';
|
||||
import { ResizeHandle } from '@ui/layout/ResizeHandle/ResizeHandle';
|
||||
import { useResizeHandle } from '@ui/layout/ResizeHandle/hooks/useResizeHandle';
|
||||
import { ThemeContext, type ThemeType } from '@ui/theme-constants';
|
||||
import {
|
||||
useTheme,
|
||||
useThemeColorScheme,
|
||||
type ThemeType,
|
||||
} from '@ui/theme-constants';
|
||||
import { type editor } from 'monaco-editor';
|
||||
import { type KeyboardEvent, useContext, useEffect, useState } from 'react';
|
||||
import { type KeyboardEvent, useEffect, useState } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import styles from './CodeEditor.module.scss';
|
||||
@@ -56,7 +60,8 @@ export const CodeEditor = ({
|
||||
contentPadding = 'default',
|
||||
autoHeight = false,
|
||||
}: CodeEditorProps) => {
|
||||
const { theme, colorScheme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const colorScheme = useThemeColorScheme();
|
||||
const [monaco, setMonaco] = useState<Monaco | undefined>(undefined);
|
||||
const [editor, setEditor] = useState<
|
||||
editor.IStandaloneCodeEditor | undefined
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './FloatingButton.module.scss';
|
||||
|
||||
@@ -37,7 +36,7 @@ export const FloatingButton = ({
|
||||
focus = false,
|
||||
to,
|
||||
}: FloatingButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
// Replaces the legacy Linaria `as` polymorphism: react-router Link when a
|
||||
// `to` is provided, a native button otherwise. Typed as any to forward all
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './FloatingIconButton.module.scss';
|
||||
|
||||
@@ -40,7 +40,7 @@ export const FloatingIconButton = ({
|
||||
onClick,
|
||||
isActive,
|
||||
}: FloatingIconButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './IconButton.module.scss';
|
||||
|
||||
@@ -40,7 +40,7 @@ export const IconButton = ({
|
||||
onClick,
|
||||
to,
|
||||
}: IconButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './InsideButton.module.scss';
|
||||
|
||||
@@ -21,7 +21,7 @@ export const InsideButton = ({
|
||||
onClick,
|
||||
disabled = false,
|
||||
}: InsideButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { type MouseEvent, useContext } from 'react';
|
||||
import { type MouseEvent } from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './LightButton.module.scss';
|
||||
|
||||
@@ -31,7 +31,7 @@ export const LightButton = ({
|
||||
type = 'button',
|
||||
onClick,
|
||||
}: LightButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { type ComponentProps, type MouseEvent, useContext } from 'react';
|
||||
import { type ComponentProps, type MouseEvent } from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './LightIconButton.module.scss';
|
||||
|
||||
@@ -35,7 +35,7 @@ export const LightIconButton = ({
|
||||
onClick,
|
||||
title,
|
||||
}: LightIconButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import React, { type FunctionComponent, useContext } from 'react';
|
||||
import React, { type FunctionComponent } from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './MainButton.module.scss';
|
||||
|
||||
@@ -31,7 +31,7 @@ export const MainButton = ({
|
||||
disabled,
|
||||
className,
|
||||
}: MainButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
// Replicates the legacy ternary exactly: fullWidth wins over width, and a
|
||||
// falsy width (0) falls back to the 'auto' default.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { clsx } from 'clsx';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './RoundedIconButton.module.scss';
|
||||
|
||||
@@ -21,7 +21,7 @@ export const RoundedIconButton = ({
|
||||
size = 'small',
|
||||
'aria-label': ariaLabel,
|
||||
}: RoundedIconButtonProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Input } from '@base-ui/react/input';
|
||||
import { clsx } from 'clsx';
|
||||
import { type ReactNode, useContext, useId, useState } from 'react';
|
||||
import { type ReactNode, useId, useState } from 'react';
|
||||
|
||||
import { IconFilter, IconSearch } from '@ui/icon';
|
||||
import { IconButton } from '@ui/input/IconButton/IconButton';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './SearchInput.module.scss';
|
||||
|
||||
@@ -35,7 +35,7 @@ export const SearchInput = ({
|
||||
'aria-label': ariaLabel,
|
||||
'aria-labelledby': ariaLabelledby,
|
||||
}: SearchInputProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const generatedId = useId();
|
||||
const inputId = id ?? generatedId;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Pill } from '@ui/data-display/Pill/Pill';
|
||||
import { Avatar } from '@ui/data-display';
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { type ReactElement, useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { type ReactElement } from 'react';
|
||||
import { StyledTabHover } from '@ui/input/TabButton/parts/StyledTabBase';
|
||||
|
||||
export type TabContentProps = {
|
||||
@@ -29,7 +29,7 @@ export const TabContent = ({
|
||||
contentSize = 'sm',
|
||||
className,
|
||||
}: TabContentProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const iconColor = active
|
||||
? theme.font.color.primary
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { VisibilityHidden } from '@ui/accessibility';
|
||||
import { IconChevronDown } from '@ui/icon';
|
||||
import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow';
|
||||
import { ThemeContext, themeCssVariables } from '@ui/theme-constants';
|
||||
import { themeCssVariables, useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import styles from './JsonArrow.module.scss';
|
||||
|
||||
@@ -16,7 +15,7 @@ export const JsonArrow = ({
|
||||
onClick: () => void;
|
||||
variant?: 'blue' | 'red';
|
||||
}) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const { arrowButtonCollapsedLabel, arrowButtonExpandedLabel } =
|
||||
useJsonTreeContextOrThrow();
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { type JsonNodeHighlighting } from '@ui/json-visualizer/types/JsonNodeHighlighting';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import styles from './JsonNodeLabel.module.scss';
|
||||
|
||||
@@ -15,7 +14,7 @@ export const JsonNodeLabel = ({
|
||||
Icon: IconComponent;
|
||||
highlighting?: JsonNodeHighlighting | undefined;
|
||||
}) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<span
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './AnimatedCircleLoading.module.scss';
|
||||
|
||||
@@ -10,7 +10,7 @@ export const AnimatedCircleLoading = ({
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { useContext } from 'react';
|
||||
import { type AnimationDuration } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type AnimatedEaseInProps = Omit<
|
||||
React.ComponentProps<typeof motion.div>,
|
||||
@@ -14,7 +13,7 @@ export const AnimatedEaseIn = ({
|
||||
children,
|
||||
duration = 'normal',
|
||||
}: AnimatedEaseInProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const initial = { opacity: 0 };
|
||||
const animate = { opacity: 1 };
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useContext } from 'react';
|
||||
import { type AnimationDuration } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type AnimatedEaseInOutProps = {
|
||||
isOpen: boolean;
|
||||
@@ -20,7 +19,7 @@ export const AnimatedEaseInOut = ({
|
||||
duration = 'normal',
|
||||
initial = true,
|
||||
}: AnimatedEaseInOutProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<AnimatePresence initial={initial}>
|
||||
|
||||
+3
-3
@@ -4,9 +4,9 @@ import { type AnimationDurations } from '@ui/layout/AnimatedExpandableContainer/
|
||||
import { type AnimationMode } from '@ui/layout/AnimatedExpandableContainer/types/AnimationMode';
|
||||
import { type AnimationSize } from '@ui/layout/AnimatedExpandableContainer/types/AnimationSize';
|
||||
import { getExpandableAnimationConfig } from '@ui/layout/AnimatedExpandableContainer/utils/getExpandableAnimationConfig';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { type ReactNode, useContext, useRef, useState } from 'react';
|
||||
import { type ReactNode, useRef, useState } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
type AnimatedExpandableContainerProps = {
|
||||
@@ -28,7 +28,7 @@ export const AnimatedExpandableContainer = ({
|
||||
containAnimation = true,
|
||||
initial = true,
|
||||
}: AnimatedExpandableContainerProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [size, setSize] = useState<AnimationSize>(0);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useContext } from 'react';
|
||||
import { type AnimationDuration } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type AnimatedFadeOutProps = {
|
||||
isOpen: boolean;
|
||||
@@ -18,7 +17,7 @@ export const AnimatedFadeOut = ({
|
||||
marginBottom,
|
||||
marginTop,
|
||||
}: AnimatedFadeOutProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './AnimatedIconCrossfade.module.scss';
|
||||
|
||||
@@ -19,7 +19,7 @@ export const AnimatedIconCrossfade = ({
|
||||
InactiveIcon,
|
||||
size,
|
||||
}: AnimatedIconCrossfadeProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const iconSize = size ?? theme.icon.size.sm;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type HTMLMotionProps, motion } from 'framer-motion';
|
||||
import { type AnimationDuration } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { type JSX, useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { type JSX } from 'react';
|
||||
|
||||
import styles from './AnimatedRotate.module.scss';
|
||||
|
||||
@@ -18,7 +18,7 @@ export const AnimatedRotate = ({
|
||||
duration = 'fast',
|
||||
animateOnHover,
|
||||
}: AnimatedRotateProps): JSX.Element => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const initial = { opacity: 0, rotate: -90 };
|
||||
const animate = { opacity: 1, rotate: 0 };
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import { useContext } from 'react';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
type AnimatedTranslationProps = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const AnimatedTranslation = ({ children }: AnimatedTranslationProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { IconBrandGithub } from '@ui/icon';
|
||||
import { ClickToActionLink } from '@ui/navigation/ClickToActionLink/ClickToActionLink';
|
||||
import { GITHUB_LINK } from '@ui/navigation/Link/constants/GithubLink';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
interface GithubVersionLinkProps {
|
||||
version: string;
|
||||
}
|
||||
|
||||
export const GithubVersionLink = ({ version }: GithubVersionLinkProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<ClickToActionLink href={GITHUB_LINK} target="_blank" rel="noreferrer">
|
||||
|
||||
@@ -6,12 +6,11 @@ import {
|
||||
type MouseEvent,
|
||||
type ReactElement,
|
||||
type ReactNode,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import { MenuItemHotKeys } from '@ui/navigation/MenuItemHotKeys/MenuItemHotKeys';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import { type Nullable } from '@ui/utilities/types/Nullable';
|
||||
import { MenuItemLeftContent } from '@ui/navigation/MenuItem/parts/MenuItemLeftContent';
|
||||
@@ -98,7 +97,7 @@ export const MenuItem = ({
|
||||
hotKeys,
|
||||
isSubMenuOpened = false,
|
||||
}: MenuItemProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
const showIconButtons = Array.isArray(iconButtons) && iconButtons.length > 0;
|
||||
|
||||
const handleMenuItemClick = (event: MouseEvent<HTMLDivElement>) => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { TintedIconTile } from '@ui/data-display';
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
import { MenuItemIconBoxContainer } from '@ui/navigation/MenuItem/parts/MenuItemIconBoxContainer';
|
||||
|
||||
@@ -19,7 +18,7 @@ export const MenuItemIcon = ({
|
||||
withContainer = false,
|
||||
withContainerBackground = true,
|
||||
}: MenuItemIconProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
if (!Icon) {
|
||||
return null;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { TintedIconTile } from '@ui/data-display';
|
||||
import { type IconComponent, IconGripVertical } from '@ui/icon';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
import { MenuItemIconBoxContainer } from '@ui/navigation/MenuItem/parts/MenuItemIconBoxContainer';
|
||||
|
||||
@@ -22,7 +21,7 @@ export const MenuItemIconWithGripSwap = ({
|
||||
withIconContainer = false,
|
||||
gripIconColor,
|
||||
}: MenuItemIconWithGripSwapProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
if (!LeftIcon) {
|
||||
return null;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { isNonEmptyString, isString } from '@sniptt/guards';
|
||||
import { type ReactNode, useContext } from 'react';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import { type IconComponent, IconGripVertical } from '@ui/icon';
|
||||
import { OverflowingTextWithTooltip } from '@ui/surfaces';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext, themeCssVariables } from '@ui/theme-constants';
|
||||
import { themeCssVariables, useTheme } from '@ui/theme-constants';
|
||||
import { type MenuItemDraggableGripMode } from '@ui/navigation/MenuItem/types/MenuItemDraggableGripMode';
|
||||
import { MenuItemIcon } from '@ui/navigation/MenuItem/parts/MenuItemIcon';
|
||||
import { MenuItemIconBoxContainer } from '@ui/navigation/MenuItem/parts/MenuItemIconBoxContainer';
|
||||
@@ -46,7 +46,7 @@ export const MenuItemLeftContent = ({
|
||||
gripMode = 'never',
|
||||
disabled = false,
|
||||
}: MenuItemLeftContentProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
const gripIconColor = withIconContainer
|
||||
? themeCssVariables.font.color.tertiary
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconChevronRight, type IconComponent } from '@ui/icon';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { MenuItemLeftContent } from '@ui/navigation/MenuItem/parts/MenuItemLeftContent';
|
||||
import {
|
||||
StyledMenuItemBase,
|
||||
@@ -22,7 +21,7 @@ export const MenuItemNavigate = ({
|
||||
className,
|
||||
onClick,
|
||||
}: MenuItemNavigateProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledMenuItemBase onClick={onClick} className={className}>
|
||||
|
||||
@@ -2,12 +2,11 @@ import { isString } from '@sniptt/guards';
|
||||
import { IconCheck, IconChevronRight, type IconComponent } from '@ui/icon';
|
||||
import { OverflowingTextWithTooltip } from '@ui/surfaces';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { clsx } from 'clsx';
|
||||
import {
|
||||
type ComponentPropsWithoutRef,
|
||||
forwardRef,
|
||||
useContext,
|
||||
type ReactNode,
|
||||
} from 'react';
|
||||
import { MenuItemLeftContent } from '@ui/navigation/MenuItem/parts/MenuItemLeftContent';
|
||||
@@ -77,7 +76,7 @@ export const MenuItemSelect = ({
|
||||
contextualText,
|
||||
contextualTextPosition = 'left',
|
||||
}: MenuItemSelectProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledMenuItemSelect
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type ReactNode, useContext } from 'react';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import {
|
||||
StyledMenuItemIconCheck,
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from '@ui/navigation/MenuItem/parts/StyledMenuItemBase';
|
||||
|
||||
import { OverflowingTextWithTooltip } from '@ui/surfaces';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { StyledMenuItemSelect } from '@ui/navigation/MenuItemSelect/MenuItemSelect';
|
||||
|
||||
import styles from './MenuItemSelectAvatar.module.scss';
|
||||
@@ -36,7 +36,7 @@ export const MenuItemSelectAvatar = ({
|
||||
focused,
|
||||
testId,
|
||||
}: MenuItemSelectAvatarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledMenuItemSelect
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
|
||||
import { ColorSample, type ColorSampleVariant } from '@ui/data-display';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import {
|
||||
DEFAULT_COLOR_LABELS,
|
||||
type ColorLabels,
|
||||
@@ -35,7 +34,7 @@ export const MenuItemSelectColor = ({
|
||||
variant = 'default',
|
||||
colorLabels = DEFAULT_COLOR_LABELS,
|
||||
}: MenuItemSelectColorProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledMenuItemSelect
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
import { Tag } from '@ui/data-display';
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { type ThemeColor } from '@ui/theme';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useContext } from 'react';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
import { StyledMenuItemSelect } from '@ui/navigation/MenuItemSelect/MenuItemSelect';
|
||||
|
||||
type MenuItemSelectTagProps = {
|
||||
@@ -33,7 +32,7 @@ export const MenuItemSelectTag = ({
|
||||
variant = 'solid',
|
||||
LeftIcon,
|
||||
}: MenuItemSelectTagProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledMenuItemSelect
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { clsx } from 'clsx';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import { type IconComponent } from '@ui/icon';
|
||||
import { AppTooltip, TooltipDelay, TooltipPosition } from '@ui/surfaces';
|
||||
import { ThemeContext } from '@ui/theme-constants';
|
||||
import { useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './MenuPicker.module.scss';
|
||||
|
||||
@@ -38,7 +37,7 @@ export const MenuPicker = ({
|
||||
tooltipDelay = TooltipDelay.noDelay,
|
||||
tooltipOffset = 5,
|
||||
}: MenuPickerProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { type IconComponent } from '@ui/icon/types/IconComponent';
|
||||
import { ThemeContext, themeCssVariables } from '@ui/theme-constants';
|
||||
import { themeCssVariables, useTheme } from '@ui/theme-constants';
|
||||
|
||||
import styles from './NavigationBarItem.module.scss';
|
||||
|
||||
@@ -18,7 +16,7 @@ export const NavigationBarItem = ({
|
||||
onClick,
|
||||
ariaLabel,
|
||||
}: NavigationBarItemProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<button
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Tooltip } from '@base-ui/react/tooltip';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { clsx } from 'clsx';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useThemeContainer } from '@ui/theme-constants';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import styles from './AppTooltip.module.scss';
|
||||
@@ -88,6 +89,8 @@ export const AppTooltip = ({
|
||||
}
|
||||
};
|
||||
|
||||
const themeContainer = useThemeContainer();
|
||||
|
||||
const [show, setShow] = useState(false);
|
||||
const [anchorElements, setAnchorElements] = useState<Element[]>([]);
|
||||
const [activeAnchor, setActiveAnchor] = useState<Element | null>(null);
|
||||
@@ -283,7 +286,7 @@ export const AppTooltip = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Portal container={themeContainer ?? undefined}>
|
||||
<Tooltip.Positioner
|
||||
anchor={activeAnchor}
|
||||
side={side}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Dialog } from '@base-ui/react/dialog';
|
||||
import { clsx } from 'clsx';
|
||||
import { useRef } from 'react';
|
||||
import { useThemeContainer } from '@ui/theme-constants';
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import { type ModalOverlay } from '@ui/surfaces/Modal/types/ModalOverlay';
|
||||
@@ -63,6 +64,11 @@ export const Modal = ({
|
||||
const internalRef = useRef<HTMLDivElement>(null);
|
||||
const resolvedRef = externalRef ?? internalRef;
|
||||
|
||||
const themeContainer = useThemeContainer();
|
||||
const resolvedContainer = isDefined(container)
|
||||
? container
|
||||
: (themeContainer ?? undefined);
|
||||
|
||||
const handleBackdropMouseDown = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onBackdropMouseDown?.(e);
|
||||
@@ -73,7 +79,7 @@ export const Modal = ({
|
||||
// Modal, open/close is fully controlled by the isOpen prop
|
||||
return (
|
||||
<Dialog.Root open={isOpen} modal={false} disablePointerDismissal>
|
||||
<Dialog.Portal container={isDefined(container) ? container : undefined}>
|
||||
<Dialog.Portal container={resolvedContainer}>
|
||||
<ModalBackdrop
|
||||
data-testid={backdropTestId}
|
||||
data-click-outside-id={backdropClickOutsideId}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { createContext, useLayoutEffect, useState } from 'react';
|
||||
import { clsx } from 'clsx';
|
||||
import { createContext, useLayoutEffect, useRef, useState } from 'react';
|
||||
|
||||
import { isDefined } from '@ui/utilities/utils/isDefined';
|
||||
|
||||
import { ThemeScopeContext } from './ThemeScopeContext';
|
||||
import { themeCssVariables } from './themeCssVariables';
|
||||
|
||||
type StringLeaves<T> = {
|
||||
@@ -47,7 +51,9 @@ export type ThemeContextType = {
|
||||
colorScheme: 'light' | 'dark';
|
||||
};
|
||||
|
||||
const computeThemeFromCss = (): ThemeType => {
|
||||
export type ThemeOverrides = Record<string, string | number>;
|
||||
|
||||
const computeThemeFromCss = (sourceElement?: HTMLElement): ThemeType => {
|
||||
if (
|
||||
typeof document === 'undefined' ||
|
||||
typeof getComputedStyle !== 'function'
|
||||
@@ -55,7 +61,9 @@ const computeThemeFromCss = (): ThemeType => {
|
||||
return themeCssVariables as unknown as ThemeType;
|
||||
}
|
||||
|
||||
const computedStyle = getComputedStyle(document.documentElement);
|
||||
const computedStyle = getComputedStyle(
|
||||
sourceElement ?? document.documentElement,
|
||||
);
|
||||
|
||||
const resolve = (obj: Record<string, unknown>): Record<string, unknown> => {
|
||||
const result: Record<string, unknown> = {};
|
||||
@@ -99,23 +107,68 @@ export const ThemeContext = createContext<ThemeContextType>({
|
||||
export const ThemeProvider = ({
|
||||
children,
|
||||
colorScheme,
|
||||
applyToRoot = true,
|
||||
overrides,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
colorScheme: 'light' | 'dark';
|
||||
applyToRoot?: boolean;
|
||||
overrides?: ThemeOverrides;
|
||||
className?: string;
|
||||
}) => {
|
||||
const isScoped = isDefined(overrides) || !applyToRoot;
|
||||
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [theme, setTheme] = useState<ThemeType>(() => {
|
||||
applyColorSchemeClass(colorScheme);
|
||||
if (applyToRoot) {
|
||||
applyColorSchemeClass(colorScheme);
|
||||
}
|
||||
return computeThemeFromCss();
|
||||
});
|
||||
const [scopeContainer, setScopeContainer] = useState<HTMLElement | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const overridesKey = isDefined(overrides) ? JSON.stringify(overrides) : '';
|
||||
|
||||
useLayoutEffect(() => {
|
||||
applyColorSchemeClass(colorScheme);
|
||||
setTheme(computeThemeFromCss());
|
||||
}, [colorScheme]);
|
||||
if (applyToRoot) {
|
||||
applyColorSchemeClass(colorScheme);
|
||||
}
|
||||
|
||||
setTheme(
|
||||
computeThemeFromCss(
|
||||
isScoped ? (wrapperRef.current ?? undefined) : undefined,
|
||||
),
|
||||
);
|
||||
setScopeContainer(isScoped ? wrapperRef.current : null);
|
||||
}, [colorScheme, applyToRoot, isScoped, overridesKey]);
|
||||
|
||||
const contextValue = { theme, colorScheme };
|
||||
|
||||
if (!isScoped) {
|
||||
return (
|
||||
<ThemeContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
const overridesStyle = (overrides ?? {}) as React.CSSProperties;
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ theme, colorScheme }}>
|
||||
{children}
|
||||
<ThemeContext.Provider value={contextValue}>
|
||||
<ThemeScopeContext.Provider value={scopeContainer}>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className={clsx(applyToRoot ? undefined : colorScheme, className)}
|
||||
style={{ display: 'contents', ...overridesStyle }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</ThemeScopeContext.Provider>
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const ThemeScopeContext = createContext<HTMLElement | null>(null);
|
||||
@@ -10,5 +10,13 @@
|
||||
export { MOBILE_VIEWPORT } from './constants';
|
||||
export { getNextThemeColor } from './getNextThemeColor';
|
||||
export { themeCssVariables } from './themeCssVariables';
|
||||
export type { ThemeType, ThemeContextType } from './ThemeProvider';
|
||||
export type {
|
||||
ThemeType,
|
||||
ThemeContextType,
|
||||
ThemeOverrides,
|
||||
} from './ThemeProvider';
|
||||
export { ThemeContext, ThemeProvider } from './ThemeProvider';
|
||||
export { ThemeScopeContext } from './ThemeScopeContext';
|
||||
export { useTheme } from './useTheme';
|
||||
export { useThemeColorScheme } from './useThemeColorScheme';
|
||||
export { useThemeContainer } from './useThemeContainer';
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { ThemeContext, type ThemeType } from './ThemeProvider';
|
||||
|
||||
export const useTheme = (): ThemeType => useContext(ThemeContext).theme;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { ThemeContext } from './ThemeProvider';
|
||||
|
||||
export const useThemeColorScheme = (): 'light' | 'dark' =>
|
||||
useContext(ThemeContext).colorScheme;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { ThemeScopeContext } from './ThemeScopeContext';
|
||||
|
||||
export const useThemeContainer = (): HTMLElement | null =>
|
||||
useContext(ThemeScopeContext);
|
||||
Reference in New Issue
Block a user