-
Notifications
You must be signed in to change notification settings - Fork 432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(manifest): add icons, tools & projectId #7980
base: next
Are you sure you want to change the base?
Changes from all commits
c0dfd10
d3cb461
96aefa3
4d5f1fd
05b5713
ee7c17a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import {ThemeProvider} from '@sanity/ui' | ||
import {buildTheme} from '@sanity/ui/theme' | ||
import {type ComponentType, createElement, isValidElement, type ReactNode} from 'react' | ||
import {isValidElementType} from 'react-is' | ||
import {createDefaultIcon} from 'sanity' | ||
import {ServerStyleSheet, StyleSheetManager} from 'styled-components' | ||
|
||
const theme = buildTheme() | ||
|
||
interface SchemaIconProps { | ||
icon?: ComponentType | ReactNode | ||
title: string | ||
subtitle?: string | ||
} | ||
|
||
const SchemaIcon = ({icon, title, subtitle}: SchemaIconProps): JSX.Element => { | ||
const sheet = new ServerStyleSheet() | ||
|
||
return ( | ||
<StyleSheetManager sheet={sheet.instance}> | ||
<ThemeProvider theme={theme}>{normalizeIcon(icon, title, subtitle)}</ThemeProvider> | ||
</StyleSheetManager> | ||
) | ||
} | ||
|
||
function normalizeIcon( | ||
icon: ComponentType | ReactNode | undefined, | ||
title: string, | ||
subtitle = '', | ||
): JSX.Element { | ||
if (isValidElementType(icon)) return createElement(icon) | ||
if (isValidElement(icon)) return icon | ||
return createDefaultIcon(title, subtitle) | ||
} | ||
|
||
export {SchemaIcon} | ||
export type {SchemaIconProps} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import {studioTheme, ThemeProvider} from '@sanity/ui' | ||
import {render as renderRTL, screen} from '@testing-library/react' | ||
import {describe, expect, it} from 'vitest' | ||
|
||
import {SchemaIcon, type SchemaIconProps} from '../Icon' | ||
|
||
const render = (props?: Partial<SchemaIconProps>) => | ||
renderRTL(<SchemaIcon title="Studio" {...props} />, { | ||
wrapper: ({children}) => <ThemeProvider theme={studioTheme}>{children}</ThemeProvider>, | ||
}) | ||
|
||
describe('SchemaIcon', () => { | ||
it("should render the title's first letter as uppercase when there is no icon present & the title is a single word", () => { | ||
render() | ||
|
||
expect(screen.getByText('S')).toBeInTheDocument() | ||
}) | ||
|
||
it('should render the first two letters of a multi-word title as uppercase when there is no icon present', () => { | ||
render({title: 'My Studio'}) | ||
|
||
expect(screen.getByText('MS')).toBeInTheDocument() | ||
}) | ||
|
||
it('should render the icon when present as a ComponentType', () => { | ||
render({ | ||
icon: () => ( | ||
<svg data-testid="icon"> | ||
<rect fill="#ff0000" height="32" width="32" /> | ||
</svg> | ||
), | ||
}) | ||
|
||
expect(screen.getByTestId('icon')).toBeInTheDocument() | ||
expect(screen.queryByText('S')).not.toBeInTheDocument() | ||
}) | ||
|
||
it('should render the icon when present as a ReactNode', () => { | ||
render({ | ||
icon: ( | ||
<svg data-testid="icon"> | ||
<rect fill="#ff0000" height="32" width="32" /> | ||
</svg> | ||
), | ||
}) | ||
|
||
expect(screen.getByTestId('icon')).toBeInTheDocument() | ||
expect(screen.queryByText('S')).not.toBeInTheDocument() | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -110,8 +110,6 @@ export interface Tool<Options = any> { | |
|
||
/** | ||
* React component for the icon representing the tool. | ||
* | ||
* @deprecated Tool icons are no longer displayed. | ||
*/ | ||
icon?: ComponentType | ||
|
||
|
@@ -175,6 +173,11 @@ export interface Tool<Options = any> { | |
params: Record<string, unknown>, | ||
payload: unknown, | ||
) => boolean | {[key: string]: boolean} | ||
|
||
/** | ||
* The type of tool – used to group tools across multiple workspaces and have a constant identifier. | ||
*/ | ||
type?: string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It says "used to group tools", but the Studio doesnt do that. It is not clear to me how we want to design types/apis for studio types that are not used by studio but only by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The type concept is a bit fuzzy to me as well. Probably missing some context. If it's for grouping, could it be a way for the tool to declare what group it belongs to, e.g. by Is the idea that the consuming end doesn't need to know what types of tools exists; i.e. it just groups the ones with similar types? Or could the consuming aware of what types exists and will do the grouping based on that?
|
||
} | ||
|
||
/** @public */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(se later comments/questions about type)