Merge pull request #27904 from backstage/canon-improve-box
Update Box component
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import { addons } from '@storybook/manager-api';
|
||||
import { create } from '@storybook/theming';
|
||||
|
||||
const theme = create({
|
||||
base: 'light',
|
||||
brandTitle: 'My custom Storybook',
|
||||
brandUrl: 'https://example.com',
|
||||
brandImage: 'logo.svg',
|
||||
brandTarget: '_self',
|
||||
});
|
||||
|
||||
addons.setConfig({
|
||||
theme,
|
||||
});
|
||||
@@ -2,6 +2,10 @@ import React from 'react';
|
||||
import type { Preview, ReactRenderer } from '@storybook/react';
|
||||
import { withThemeByDataAttribute } from '@storybook/addon-themes';
|
||||
|
||||
// Storybook specific styles
|
||||
import '../docs/components/styles.css';
|
||||
|
||||
// Canon specific styles
|
||||
import '../src/theme/styles.css';
|
||||
|
||||
const preview: Preview = {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Unstyled } from '@storybook/blocks';
|
||||
import { Columns, Text, ComponentStatus, Banner } from './components';
|
||||
import { Columns, Text, ComponentStatus, Banner, Title } from './components';
|
||||
|
||||
<Unstyled>
|
||||
|
||||
<img src="header.png" style={{ width: '100%', marginTop: '-16px' }} />
|
||||
|
||||
<Text style={{ marginTop: '64px' }}>
|
||||
<Text style={{ marginTop: '64px', marginBottom: '24px' }}>
|
||||
Welcome to the Canon, the new design library for Backstage plugins. This
|
||||
project is still under active development but we will make sure to document
|
||||
the API as we go. We are aiming to improve the general UI of Backstage and
|
||||
@@ -18,32 +18,62 @@ import { Columns, Text, ComponentStatus, Banner } from './components';
|
||||
will change until we reach a stable release.
|
||||
</Banner>
|
||||
|
||||
<Columns style={{ marginTop: '64px' }}>
|
||||
<Title style={{ marginTop: '48px' }} type="h2">
|
||||
Project Status
|
||||
</Title>
|
||||
<Text>
|
||||
We are still in the process of documenting the API and building the
|
||||
components. You can use the statuses below to see what is ready and what is
|
||||
coming soon. If there is a component missing that you need, please let us know
|
||||
by opening an issue on GitHub.
|
||||
</Text>
|
||||
|
||||
<Columns style={{ marginTop: '32px' }}>
|
||||
<ComponentStatus name="Storybook setup" status="done" />
|
||||
<ComponentStatus
|
||||
name="Iconography"
|
||||
status="done"
|
||||
link="/?path=/docs/iconography--docs"
|
||||
/>
|
||||
<ComponentStatus name="Global tokens" status="inProgress" />
|
||||
<ComponentStatus
|
||||
name="Theming system"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/theme--docs"
|
||||
/>
|
||||
<ComponentStatus name="Storybook setup" status="inProgress" />
|
||||
<ComponentStatus name="Tokens" status="inProgress" />
|
||||
<ComponentStatus
|
||||
name="Box"
|
||||
name="Box component"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/components-box--docs"
|
||||
/>
|
||||
<ComponentStatus
|
||||
name="Button"
|
||||
name="Inline component"
|
||||
status="inProgress"
|
||||
link="/?path=/story/components-inline--default"
|
||||
/>
|
||||
<ComponentStatus
|
||||
name="Stack component"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/components-stack--default"
|
||||
/>
|
||||
<ComponentStatus
|
||||
name="Button component"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/components-button--docs"
|
||||
/>
|
||||
<ComponentStatus name="Input" status="notStarted" />
|
||||
<ComponentStatus name="Select" status="notStarted" />
|
||||
<ComponentStatus name="Checkbox" status="notStarted" />
|
||||
<ComponentStatus name="Radio" status="notStarted" />
|
||||
<ComponentStatus name="Switch" status="notStarted" />
|
||||
<ComponentStatus name="Tooltip" status="notStarted" />
|
||||
<ComponentStatus name="Header" status="notStarted" />
|
||||
<ComponentStatus name="Tabs" status="notStarted" />
|
||||
<ComponentStatus
|
||||
name="Icon component"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/components-icon--docs"
|
||||
/>
|
||||
<ComponentStatus name="Input component" status="notStarted" />
|
||||
<ComponentStatus name="Select component" status="notStarted" />
|
||||
<ComponentStatus name="Checkbox component" status="notStarted" />
|
||||
<ComponentStatus name="Radio component" status="notStarted" />
|
||||
<ComponentStatus name="Switch component" status="notStarted" />
|
||||
<ComponentStatus name="Tooltip component" status="notStarted" />
|
||||
<ComponentStatus name="Header component" status="notStarted" />
|
||||
<ComponentStatus name="Tabs component" status="notStarted" />
|
||||
</Columns>
|
||||
|
||||
</Unstyled>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Unstyled, Source } from '@storybook/blocks';
|
||||
import { Title, Text, IconLibrary } from './components';
|
||||
|
||||
<Unstyled>
|
||||
|
||||
<Title type="h1">Iconography</Title>
|
||||
|
||||
<Text>
|
||||
All our default icons are provided by [Remix Icon](https://remixicon.com/). We
|
||||
don't import all icons to reduce the bundle size but we cherry pick a nice
|
||||
selection for you to use in your application. The list of names is set down
|
||||
below. To use an icon, you can use the `Icon` component and pass the name of
|
||||
the icon you want to use.
|
||||
</Text>
|
||||
|
||||
<Source code={`<Icon name="heart" />`} language="tsx" dark />
|
||||
|
||||
<IconLibrary />
|
||||
|
||||
</Unstyled>
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Icon } from '@backstage/canon';
|
||||
import type { IconNames } from '@backstage/canon';
|
||||
import { defaultIcons } from '../../../src/components/Icon/icons';
|
||||
import { Text } from '../Text';
|
||||
|
||||
export const IconLibrary = () => {
|
||||
const icons = Object.keys(defaultIcons);
|
||||
|
||||
return (
|
||||
<div className="icon-library">
|
||||
{icons.map(icon => (
|
||||
<div key={icon} className="icon-library-item">
|
||||
<div className="icon-library-item-icon">
|
||||
<Icon name={icon as IconNames} />
|
||||
</div>
|
||||
<Text>{icon}</Text>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
.icon-library {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.icon-library-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.icon-library-item-icon {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
border: 1px solid #d3d3d3;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
@@ -22,3 +22,4 @@ export * from './Columns';
|
||||
export * from './ComponentStatus';
|
||||
export * from './LayoutComponents';
|
||||
export * from './Banner';
|
||||
export * from './IconLibrary';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
@import './IconLibrary/styles.css';
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 127 KiB |
@@ -38,11 +38,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@base_ui/react": "^1.0.0-alpha.3",
|
||||
"@remixicon/react": "^4.5.0",
|
||||
"@vanilla-extract/css": "^1.16.0",
|
||||
"@vanilla-extract/dynamic": "^2.1.2",
|
||||
"@vanilla-extract/recipes": "^0.5.5",
|
||||
"@vanilla-extract/sprinkles": "^1.6.3",
|
||||
"lucide-react": "^0.460.0"
|
||||
"@vanilla-extract/sprinkles": "^1.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
|
||||
+235
-1458
File diff suppressed because it is too large
Load Diff
@@ -17,19 +17,7 @@
|
||||
import { createElement } from 'react';
|
||||
import { boxSprinkles } from './sprinkles.css';
|
||||
import { base } from './box.css';
|
||||
|
||||
/**
|
||||
* Properties for {@link Box}
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type BoxProps = Parameters<typeof boxSprinkles>[0] &
|
||||
Omit<
|
||||
React.AllHTMLAttributes<HTMLElement>,
|
||||
keyof Parameters<typeof boxSprinkles>[0]
|
||||
> & {
|
||||
as?: keyof JSX.IntrinsicElements;
|
||||
};
|
||||
import { BoxProps } from './types';
|
||||
|
||||
/** @public */
|
||||
export const Box = (props: BoxProps) => {
|
||||
|
||||
@@ -20,8 +20,6 @@ import { Chip } from '../../../../docs/components';
|
||||
import { listResponsiveValues } from '../../../utils/list-values';
|
||||
import { responsiveProperties } from '../sprinkles.css';
|
||||
|
||||
console.log(responsiveProperties.styles);
|
||||
|
||||
export const SpacingTable = () => {
|
||||
return (
|
||||
<Table.Root>
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Box } from './Box';
|
||||
export type { BoxProps } from './Box';
|
||||
export { boxSprinkles } from './sprinkles.css';
|
||||
export type * from './types';
|
||||
export { breakpoints, space, themes } from './properties';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** @public */
|
||||
export const breakpoints = {
|
||||
xs: {},
|
||||
sm: { '@media': 'screen and (min-width: 640px)' },
|
||||
@@ -23,6 +24,13 @@ export const breakpoints = {
|
||||
'2xl': { '@media': 'screen and (min-width: 1536px)' },
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export const themes = {
|
||||
light: { selector: '[data-theme="light"] &' },
|
||||
dark: { selector: '[data-theme="dark"] &' },
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export const space = {
|
||||
none: 0,
|
||||
xxs: 'var(--canon-space-xxs)',
|
||||
|
||||
@@ -97,7 +97,6 @@ export const colorProperties = defineProperties({
|
||||
},
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export const boxSprinkles = createSprinkles(
|
||||
responsiveProperties,
|
||||
colorProperties,
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { breakpoints, space, themes } from './properties';
|
||||
|
||||
/** @public */
|
||||
export type Breakpoint = keyof typeof breakpoints;
|
||||
|
||||
/** @public */
|
||||
export type Space = keyof typeof space;
|
||||
|
||||
/** @public */
|
||||
export type Theme = keyof typeof themes;
|
||||
|
||||
/** @public */
|
||||
export type Display =
|
||||
| 'flex'
|
||||
| 'none'
|
||||
| 'inline'
|
||||
| 'block'
|
||||
| Partial<Record<Breakpoint, 'flex' | 'none' | 'inline' | 'block'>>;
|
||||
|
||||
/** @public */
|
||||
export type FlexDirection =
|
||||
| 'row'
|
||||
| 'column'
|
||||
| Partial<Record<Breakpoint, 'row' | 'column'>>;
|
||||
|
||||
/** @public */
|
||||
export type FlexWrap =
|
||||
| 'wrap'
|
||||
| 'nowrap'
|
||||
| Partial<Record<Breakpoint, 'wrap' | 'nowrap'>>;
|
||||
|
||||
/** @public */
|
||||
export type JustifyContent =
|
||||
| 'stretch'
|
||||
| 'flex-start'
|
||||
| 'center'
|
||||
| 'flex-end'
|
||||
| 'space-around'
|
||||
| 'space-between'
|
||||
| Partial<
|
||||
Record<
|
||||
Breakpoint,
|
||||
| 'stretch'
|
||||
| 'flex-start'
|
||||
| 'center'
|
||||
| 'flex-end'
|
||||
| 'space-around'
|
||||
| 'space-between'
|
||||
>
|
||||
>;
|
||||
|
||||
/** @public */
|
||||
export type AlignItems =
|
||||
| 'stretch'
|
||||
| 'flex-start'
|
||||
| 'center'
|
||||
| 'flex-end'
|
||||
| Partial<
|
||||
Record<Breakpoint, 'stretch' | 'flex-start' | 'center' | 'flex-end'>
|
||||
>;
|
||||
|
||||
/** @public */
|
||||
export type BorderRadius =
|
||||
| 'none'
|
||||
| 'small'
|
||||
| 'medium'
|
||||
| 'full'
|
||||
| Partial<Record<Breakpoint, 'none' | 'small' | 'medium' | 'full'>>;
|
||||
|
||||
/** @public */
|
||||
export type Gap = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type PaddingLeft = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type PaddingRight = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type PaddingTop = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type PaddingBottom = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type Padding = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type PaddingX = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type PaddingY = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type MarginLeft = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type MarginRight = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type MarginTop = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type MarginBottom = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type Margin = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type MarginX = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type MarginY = Space | Partial<Record<Breakpoint, Space>>;
|
||||
|
||||
/** @public */
|
||||
export type Background =
|
||||
| 'background'
|
||||
| 'elevation1'
|
||||
| 'elevation2'
|
||||
| 'transparent'
|
||||
| Partial<
|
||||
Record<Theme, 'background' | 'elevation1' | 'elevation2' | 'transparent'>
|
||||
>;
|
||||
|
||||
/** @public */
|
||||
export type Color =
|
||||
| 'primary'
|
||||
| 'secondary'
|
||||
| 'error'
|
||||
| Partial<Record<Theme, 'primary' | 'secondary' | 'error'>>;
|
||||
|
||||
/** @public */
|
||||
export interface BoxProps {
|
||||
as?: keyof JSX.IntrinsicElements;
|
||||
background?: Background;
|
||||
children?: React.ReactNode;
|
||||
color?: Color;
|
||||
display?: Display;
|
||||
flexDirection?: FlexDirection;
|
||||
flexWrap?: FlexWrap;
|
||||
justifyContent?: JustifyContent;
|
||||
alignItems?: AlignItems;
|
||||
borderRadius?: BorderRadius;
|
||||
gap?: Gap;
|
||||
padding?: Padding;
|
||||
paddingLeft?: PaddingLeft;
|
||||
paddingRight?: PaddingRight;
|
||||
paddingTop?: PaddingTop;
|
||||
paddingBottom?: PaddingBottom;
|
||||
paddingX?: PaddingX;
|
||||
paddingY?: PaddingY;
|
||||
margin?: Margin;
|
||||
marginLeft?: MarginLeft;
|
||||
marginRight?: MarginRight;
|
||||
marginTop?: MarginTop;
|
||||
marginBottom?: MarginBottom;
|
||||
marginX?: MarginX;
|
||||
marginY?: MarginY;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
@@ -71,9 +71,9 @@ export const WithIcons: Story = {
|
||||
},
|
||||
render: args => (
|
||||
<div style={{ display: 'flex', gap: '10px' }}>
|
||||
<Button {...args} iconStart="Cloud" />
|
||||
<Button {...args} iconEnd="ArrowRight" />
|
||||
<Button {...args} iconStart="Cloud" iconEnd="ArrowRight" />
|
||||
<Button {...args} iconStart="cloud" />
|
||||
<Button {...args} iconEnd="arrowRight" />
|
||||
<Button {...args} iconStart="cloud" iconEnd="arrowRight" />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
@@ -84,9 +84,9 @@ export const FullWidth: Story = {
|
||||
},
|
||||
render: args => (
|
||||
<Box>
|
||||
<Button {...args} iconStart="Cloud" />
|
||||
<Button {...args} iconEnd="ArrowRight" />
|
||||
<Button {...args} iconStart="Cloud" iconEnd="ArrowRight" />
|
||||
<Button {...args} iconStart="cloud" />
|
||||
<Button {...args} iconEnd="arrowRight" />
|
||||
<Button {...args} iconStart="cloud" iconEnd="arrowRight" />
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
import React from 'react';
|
||||
import { button } from './button.css';
|
||||
import { Box } from '../Box/Box';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { IconNames } from '../Icon/context';
|
||||
import type { IconNames } from '../Icon/types';
|
||||
|
||||
/**
|
||||
* Properties for {@link Button}
|
||||
@@ -45,16 +44,15 @@ export const Button = ({
|
||||
...props
|
||||
}: ButtonProps) => {
|
||||
return (
|
||||
<Box
|
||||
<button
|
||||
{...props}
|
||||
as="button"
|
||||
disabled={disabled}
|
||||
className={button({ size, variant, disabled })}
|
||||
>
|
||||
{iconStart && <Icon name={iconStart} />}
|
||||
{children}
|
||||
{iconEnd && <Icon name={iconEnd} />}
|
||||
</Box>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
import React from 'react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { Icon } from './Icon';
|
||||
import { IconProvider } from './context';
|
||||
import * as LucideIcons from 'lucide-react';
|
||||
import { ThemeProvider } from '../../theme/context';
|
||||
import { defaultIcons } from './icons';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Icon',
|
||||
@@ -26,15 +26,14 @@ const meta = {
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
name: {
|
||||
control: 'select',
|
||||
options: Object.keys(LucideIcons),
|
||||
options: Object.keys(defaultIcons),
|
||||
},
|
||||
},
|
||||
args: {
|
||||
name: 'ArrowDown',
|
||||
name: 'heart',
|
||||
},
|
||||
} satisfies Meta<typeof Icon>;
|
||||
|
||||
@@ -43,40 +42,19 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
name: 'ArrowDown',
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomIcon: Story = {
|
||||
args: {
|
||||
name: 'CustomIcon',
|
||||
name: 'heart',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithCustomIcon: Story = {
|
||||
args: {
|
||||
name: 'ArrowDown',
|
||||
name: 'arrowDown',
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<IconProvider overrides={{ ArrowDown: () => <div>Custom Icon</div> }}>
|
||||
<ThemeProvider overrides={{ arrowDown: () => <div>Custom Icon</div> }}>
|
||||
<Story />
|
||||
</IconProvider>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export const WithCustomIconOverride: Story = {
|
||||
args: {
|
||||
name: 'CustomIcon',
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<IconProvider
|
||||
overrides={{ CustomIcon: () => <div>Custom Super Icon</div> }}
|
||||
>
|
||||
<Story />
|
||||
</IconProvider>
|
||||
</ThemeProvider>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -15,18 +15,19 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useIcons, IconNames } from './context';
|
||||
import { useTheme } from '../../theme/context';
|
||||
import type { IconNames } from './types';
|
||||
|
||||
/** @public */
|
||||
export const Icon = ({ name }: { name: IconNames }) => {
|
||||
const { icons } = useIcons();
|
||||
const { icons } = useTheme();
|
||||
|
||||
const LucideIcon = icons[name];
|
||||
const RemixIcon = icons[name];
|
||||
|
||||
if (!LucideIcon) {
|
||||
if (!RemixIcon) {
|
||||
console.error(`Icon "${name}" not found.`);
|
||||
return <svg />; // Return default icon perhaps?
|
||||
}
|
||||
|
||||
return <LucideIcon />;
|
||||
return <RemixIcon />;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// We can add custom icons to the list outside of Remix
|
||||
|
||||
import type { IconMap } from './types';
|
||||
import {
|
||||
RiHeartFill,
|
||||
RiArrowDownFill,
|
||||
RiCloudFill,
|
||||
RiArrowLeftFill,
|
||||
RiArrowRightFill,
|
||||
RiArrowUpFill,
|
||||
RiDeleteBin6Line,
|
||||
RiAddLine,
|
||||
} from '@remixicon/react';
|
||||
|
||||
// List of default icons
|
||||
export const defaultIcons: IconMap = {
|
||||
arrowDown: RiArrowDownFill,
|
||||
arrowLeft: RiArrowLeftFill,
|
||||
arrowRight: RiArrowRightFill,
|
||||
arrowUp: RiArrowUpFill,
|
||||
cloud: RiCloudFill,
|
||||
heart: RiHeartFill,
|
||||
plus: RiAddLine,
|
||||
trash: RiDeleteBin6Line,
|
||||
};
|
||||
@@ -15,5 +15,4 @@
|
||||
*/
|
||||
|
||||
export * from './Icon';
|
||||
export { IconProvider } from './context';
|
||||
export type { IconNames } from './context';
|
||||
export type * from './types';
|
||||
|
||||
+12
-6
@@ -14,10 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
/** @public */
|
||||
export type IconNames =
|
||||
| 'arrowDown'
|
||||
| 'arrowLeft'
|
||||
| 'arrowRight'
|
||||
| 'arrowUp'
|
||||
| 'cloud'
|
||||
| 'heart'
|
||||
| 'plus'
|
||||
| 'trash';
|
||||
|
||||
export const CustomIcon = () => (
|
||||
<svg viewBox="0 0 24 24" fill="red" width={24} height={24}>
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" />
|
||||
</svg>
|
||||
);
|
||||
/** @public */
|
||||
export type IconMap = Partial<Record<IconNames, React.ComponentType>>;
|
||||
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, BoxProps } from '../Box/Box';
|
||||
import { Box } from '../Box/Box';
|
||||
import { alignToFlexAlign } from '../../utils/align';
|
||||
import type { BoxProps } from '../Box/types';
|
||||
|
||||
export const validInlineComponents = [
|
||||
'div',
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, BoxProps } from '../Box/Box';
|
||||
import { Box } from '../Box/Box';
|
||||
import { alignToFlexAlign } from '../../utils/align';
|
||||
|
||||
import type { BoxProps } from '../Box/types';
|
||||
const validStackComponents = [
|
||||
'div',
|
||||
'span',
|
||||
|
||||
+10
-30
@@ -15,39 +15,19 @@
|
||||
*/
|
||||
|
||||
import React, { createContext, useContext, ReactNode } from 'react';
|
||||
import { ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Cloud } from 'lucide-react';
|
||||
import { CustomIcon } from './custom-icon';
|
||||
import { IconMap, IconNames } from '../components/Icon/types';
|
||||
import { defaultIcons } from '../components/Icon/icons';
|
||||
|
||||
// List of icons available that can also be overridden.
|
||||
/** @public */
|
||||
export type IconNames =
|
||||
| 'ArrowDown'
|
||||
| 'ArrowLeft'
|
||||
| 'ArrowRight'
|
||||
| 'ArrowUp'
|
||||
| 'Cloud'
|
||||
| 'CustomIcon';
|
||||
|
||||
type IconMap = Partial<Record<IconNames, React.ComponentType>>;
|
||||
|
||||
interface IconContextProps {
|
||||
interface ThemeContextProps {
|
||||
icons: IconMap;
|
||||
}
|
||||
|
||||
// Create a default icon map with only the necessary icons
|
||||
const defaultIcons: IconMap = {
|
||||
ArrowDown,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
ArrowUp,
|
||||
Cloud,
|
||||
CustomIcon,
|
||||
};
|
||||
|
||||
const IconContext = createContext<IconContextProps>({ icons: defaultIcons });
|
||||
const ThemeContext = createContext<ThemeContextProps>({
|
||||
icons: defaultIcons,
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export const IconProvider = ({
|
||||
export const ThemeProvider = ({
|
||||
children,
|
||||
overrides,
|
||||
}: {
|
||||
@@ -58,11 +38,11 @@ export const IconProvider = ({
|
||||
const combinedIcons = { ...defaultIcons, ...overrides };
|
||||
|
||||
return (
|
||||
<IconContext.Provider value={{ icons: combinedIcons }}>
|
||||
<ThemeContext.Provider value={{ icons: combinedIcons }}>
|
||||
{children}
|
||||
</IconContext.Provider>
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export const useIcons = () => useContext(IconContext);
|
||||
export const useTheme = () => useContext(ThemeContext);
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg width="640" height="640" viewBox="0 0 640 640" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M370.766 153.765C377.563 166.716 371.236 182.114 359.357 190.647C323.005 216.758 299.326 259.411 299.326 307.597C299.326 365.997 334.107 416.27 384.077 438.817C395.235 443.852 403.478 454.368 403.478 466.609V640H382.864C224.433 640 96 511.517 96 353.025L96 20.6143C96 9.22934 105.229 0 116.614 0V0C226.982 3.14552e-06 322.792 62.3523 370.766 153.765Z" fill="black"/>
|
||||
<path d="M438.772 411.19C496.335 411.19 543 364.454 543 306.803C543 249.152 496.335 202.417 438.772 202.417C381.208 202.417 334.543 249.152 334.543 306.803C334.543 364.454 381.208 411.19 438.772 411.19Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 702 B |
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 127 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="89" height="27" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M77.414 9.71h3.036v2.992l-.264-.022c.279-.88.748-1.65 1.408-2.31.675-.66 1.533-.99 2.574-.99 1.086 0 1.9.352 2.442 1.056.558.689.836 1.598.836 2.728v7.502H84.41v-6.6c0-.66-.117-1.159-.352-1.496-.234-.338-.623-.506-1.166-.506-.601 0-1.122.271-1.562.814a4.321 4.321 0 0 0-.88 1.848v5.94h-3.036V9.71ZM69.868 21.04c-1.13 0-2.142-.257-3.036-.77a5.547 5.547 0 0 1-2.068-2.09c-.484-.895-.726-1.892-.726-2.992 0-1.115.242-2.112.726-2.992a5.503 5.503 0 0 1 2.068-2.112c.88-.514 1.892-.77 3.036-.77 1.144 0 2.156.256 3.036.77a5.347 5.347 0 0 1 2.046 2.112c.498.88.748 1.87.748 2.97 0 1.114-.25 2.12-.748 3.014a5.343 5.343 0 0 1-2.068 2.09c-.88.513-1.885.77-3.014.77Zm0-2.618c.557 0 1.048-.132 1.474-.396a2.79 2.79 0 0 0 .99-1.144c.234-.499.352-1.064.352-1.694 0-.63-.118-1.188-.352-1.672a2.764 2.764 0 0 0-.99-1.166c-.426-.279-.917-.418-1.474-.418-.558 0-1.05.14-1.474.418a2.764 2.764 0 0 0-.99 1.166c-.22.484-.33 1.041-.33 1.672 0 .63.11 1.195.33 1.694.234.484.564.865.99 1.144.425.264.916.396 1.474.396ZM52.385 9.71h3.036v2.992l-.264-.022c.279-.88.748-1.65 1.408-2.31.675-.66 1.533-.99 2.574-.99 1.085 0 1.9.352 2.442 1.056.557.689.836 1.598.836 2.728v7.502h-3.036v-6.6c0-.66-.117-1.159-.352-1.496-.235-.338-.623-.506-1.166-.506-.601 0-1.122.271-1.562.814a4.321 4.321 0 0 0-.88 1.848v5.94h-3.036V9.71ZM43.904 20.952c-1.026 0-1.87-.308-2.53-.924-.66-.616-.99-1.416-.99-2.398 0-1.115.418-2.01 1.254-2.684.85-.69 2.105-1.034 3.762-1.034h2.75l-.924.352v-.462c0-.572-.176-1.02-.528-1.342-.352-.338-.931-.506-1.738-.506-.69 0-1.386.154-2.09.462-.704.308-1.29.69-1.76 1.144v-2.882c.47-.352 1.1-.66 1.892-.924a7.942 7.942 0 0 1 2.486-.396c1.599 0 2.78.41 3.542 1.232.778.806 1.166 1.914 1.166 3.322v5.742c0 .176.008.352.022.528.03.161.066.322.11.484h-3.014v-3.3l.044 1.386a4.044 4.044 0 0 1-1.32 1.606c-.572.396-1.283.594-2.134.594Zm.858-2.156c.558 0 1.049-.206 1.474-.616.44-.426.77-.954.99-1.584v-.792h-1.562c-.762 0-1.334.146-1.716.44-.381.278-.572.674-.572 1.188 0 .41.125.74.374.99.264.25.602.374 1.012.374ZM34.66 21.04c-1.525 0-2.874-.345-4.047-1.034-1.174-.704-2.09-1.68-2.75-2.926-.646-1.247-.968-2.662-.968-4.246 0-1.584.322-2.992.968-4.224.66-1.232 1.576-2.193 2.75-2.882 1.173-.704 2.522-1.056 4.048-1.056.968 0 1.818.11 2.552.33.748.22 1.356.506 1.826.858v3.498c-.396-.484-.96-.895-1.694-1.232-.719-.338-1.51-.506-2.376-.506-.939 0-1.775.22-2.508.66-.719.44-1.284 1.056-1.694 1.848-.396.792-.594 1.694-.594 2.706 0 1.026.198 1.943.594 2.75.41.792.975 1.408 1.694 1.848.733.44 1.57.66 2.508.66.88 0 1.68-.162 2.398-.484.718-.323 1.276-.726 1.672-1.21v3.41a5.686 5.686 0 0 1-1.87.902c-.704.22-1.54.33-2.508.33ZM11.275 6.271c.276.526.019 1.152-.464 1.498a5.846 5.846 0 0 0 1.004 10.082c.454.205.789.632.789 1.13v6.206a.837.837 0 0 1-.838.837C5.33 26.024.112 20.804.112 14.366V.862C.112.399.487.024.95.024c4.483 0 8.376 2.533 10.325 6.247Z" fill="#000"/><path d="M14.037 16.729a4.237 4.237 0 0 0 4.234-4.24 4.237 4.237 0 0 0-4.234-4.242 4.237 4.237 0 0 0-4.234 4.241 4.237 4.237 0 0 0 4.234 4.24Z" fill="#000"/></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -3823,6 +3823,7 @@ __metadata:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@base_ui/react": ^1.0.0-alpha.3
|
||||
"@chromatic-com/storybook": ^3.2.2
|
||||
"@remixicon/react": ^4.5.0
|
||||
"@storybook/addon-essentials": ^8.4.5
|
||||
"@storybook/addon-interactions": ^8.4.5
|
||||
"@storybook/addon-styling-webpack": ^1.0.1
|
||||
@@ -3843,7 +3844,6 @@ __metadata:
|
||||
"@vanilla-extract/webpack-plugin": ^2.3.14
|
||||
eslint-plugin-storybook: ^0.11.1
|
||||
globals: ^15.11.0
|
||||
lucide-react: ^0.460.0
|
||||
mini-css-extract-plugin: ^2.9.2
|
||||
react: ^18.0.2
|
||||
react-dom: ^18.0.2
|
||||
@@ -15458,6 +15458,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@remixicon/react@npm:^4.5.0":
|
||||
version: 4.5.0
|
||||
resolution: "@remixicon/react@npm:4.5.0"
|
||||
peerDependencies:
|
||||
react: ">=18.2.0"
|
||||
checksum: e37b61090954954601d35367a740b7be30c105a49f67eaa5a697db16d4668d71d9fd94b339da6d449a254736d5af3b567d3694021b79d3c82fe28afb818830bc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@repeaterjs/repeater@npm:^3.0.4":
|
||||
version: 3.0.5
|
||||
resolution: "@repeaterjs/repeater@npm:3.0.5"
|
||||
@@ -35193,15 +35202,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lucide-react@npm:^0.460.0":
|
||||
version: 0.460.0
|
||||
resolution: "lucide-react@npm:0.460.0"
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
|
||||
checksum: 6106dc16dd7ce7928d6136e81c9e84e87e1b6b0910a0c78777a387c795c0512755e8bf4c602ab8f09518919999a494ed86ba7190863e8e7aec6c82665147ead3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lunr@npm:^2.3.9":
|
||||
version: 2.3.9
|
||||
resolution: "lunr@npm:2.3.9"
|
||||
|
||||
Reference in New Issue
Block a user