Skip to content

Commit

Permalink
feat(js): Auto apply generic appearance keys via style() (#6041)
Browse files Browse the repository at this point in the history
  • Loading branch information
desiprisg authored Jul 11, 2024
1 parent e04f254 commit 5cb46a1
Show file tree
Hide file tree
Showing 15 changed files with 336 additions and 182 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@
"@types/inquirer": "8.2.10",
"@types/jest": "29.5.2",
"@types/node": "^20.14.10",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"auto": "^10.36.5",
"chalk": "4.1.2",
"chalk-animation": "^1.6.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/js/src/ui/components/Header/ActionsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const ActionsContainer = () => {
<MoreActionsDropdown />
<button
class={style(
['button', 'settingsIconContainer'],
'settings__button',
`nt-h-6 nt-w-6 nt-flex nt-justify-center nt-items-center nt-rounded-md
nt-relative hover:nt-bg-foreground-alpha-50 nt-text-foreground-alpha-600`
)}
Expand Down
5 changes: 1 addition & 4 deletions packages/js/src/ui/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ import { StatusDropdown } from './StatusDropdown';

export const Header = () => {
const style = useStyle();
const { id } = useAppearance();

return (
<div
class={style('inboxHeader', cn(id, 'nt-flex nt-justify-between nt-items-center nt-self-stretch nt-py-5 nt-px-6'))}
>
<div class={style('inboxHeader', cn('nt-flex nt-justify-between nt-items-center nt-self-stretch nt-py-5 nt-px-6'))}>
<StatusDropdown />
<ActionsContainer />
</div>
Expand Down
6 changes: 2 additions & 4 deletions packages/js/src/ui/components/Header/MoreActionsDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ export const MoreActionsDropdown = () => {

return (
<Popover fallbackPlacements={['bottom', 'top']} placement="bottom">
<Popover.Trigger
classes={style(['dropdownTrigger', 'moreActionsDropdownTrigger'], moreActionsDropdownTriggerClasses())}
>
<Popover.Trigger classes={style('moreActions__dropdownTrigger', moreActionsDropdownTriggerClasses())}>
<DotsMenu />
</Popover.Trigger>
<Popover.Content classes={style(['dropdownContent', 'moreActionsDropdownContent'], dropdownContentClasses())}>
<Popover.Content classes={style('moreActions__dropdownContent', dropdownContentClasses())}>
<MoreActionsOptions />
</Popover.Content>
</Popover>
Expand Down
8 changes: 4 additions & 4 deletions packages/js/src/ui/components/Header/MoreActionsOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ export const ActionsItem = (props: { label: string; onClick: () => void; icon: (

return (
<Popover.Close onClick={props.onClick}>
<button class={style('moreActionsDropdownItem', dropdownItemClasses())}>
<span class={style('moreActionsDropdownItemLabelContainer', dropdownItemLabelContainerClasses())}>
<span class={style('moreActionsDropdownItemLeftIcon', '')}>{props.icon()}</span>
<span class={style('moreActionsDropdownItemLabel', dropdownItemLabelClasses())}>{props.label}</span>
<button class={style('moreActions__dropdownItem', dropdownItemClasses())}>
<span class={style('moreActions__dropdownItemLabelContainer', dropdownItemLabelContainerClasses())}>
<span class={style('moreActions__dropdownItemLeftIcon', '')}>{props.icon()}</span>
<span class={style('moreActions__dropdownItemLabel', dropdownItemLabelClasses())}>{props.label}</span>
</span>
</button>
</Popover.Close>
Expand Down
8 changes: 3 additions & 5 deletions packages/js/src/ui/components/Header/StatusDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,15 @@ export const StatusDropdown = () => {

return (
<Popover fallbackPlacements={['bottom', 'top']} placement="bottom">
<Popover.Trigger
classes={style(['dropdownTrigger', 'inboxStatusDropdownTrigger'], inboxStatusDropdownTriggerClasses())}
>
<span class={style('inboxStatusTitle', cn(id, 'nt-text-xl nt-font-semibold nt-text-foreground'))}>
<Popover.Trigger classes={style('inboxStatus__dropdownTrigger', inboxStatusDropdownTriggerClasses())}>
<span class={style('inboxStatus__title', cn('nt-text-xl nt-font-semibold nt-text-foreground'))}>
{getStatusLabel(feedOptions.status)}
</span>
<span>
<ArrowDropDown />
</span>
</Popover.Trigger>
<Popover.Content classes={style(['dropdownContent', 'inboxStatusDropdownContent'], dropdownContentClasses())}>
<Popover.Content classes={style('inboxStatus__dropdownContent', dropdownContentClasses())}>
<StatusOptions setFeedOptions={setFeedOptions} />
</Popover.Content>
</Popover>
Expand Down
10 changes: 5 additions & 5 deletions packages/js/src/ui/components/Header/StatusOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ export const StatusItem = (props: {

return (
<Popover.Close onClick={props.onClick}>
<button class={style('inboxStatusDropdownItem', dropdownItemClasses())}>
<span class={style('inboxStatusDropdownItemLabelContainer', dropdownItemLabelContainerClasses())}>
<span class={style('inboxStatusDropdownItemLeftIcon', '')}>{props.icon()}</span>
<span class={style('inboxStatusDropdownItemLabel', dropdownItemLabelClasses())}>{props.label}</span>
<button class={style('inboxStatus__dropdownItem', dropdownItemClasses())}>
<span class={style('inboxStatus__dropdownItemLabelContainer', dropdownItemLabelContainerClasses())}>
<span class={style('inboxStatus__dropdownItemLeftIcon', '')}>{props.icon()}</span>
<span class={style('inboxStatus__dropdownItemLabel', dropdownItemLabelClasses())}>{props.label}</span>
</span>
<Show when={props.isSelected}>
<span class={style('inboxStatusDropdownItemRightIcon', '')}>
<span class={style('inboxStatus__dropdownItemRightIcon', '')}>
<Check />
</span>
</Show>
Expand Down
6 changes: 3 additions & 3 deletions packages/js/src/ui/components/Popover/PopoverContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ export const PopoverContent: ParentComponent<{ classes: string }> = (props) => {
],
});

const handleClickOutside = (e: any) => {
if (contentRef()?.contains(e.target)) return;
const handleClickOutside = (e: MouseEvent) => {
if (contentRef()?.contains(e.target as Node)) return;
onClose();
};

const handleEscapeKey = (e: any) => {
const handleEscapeKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
Expand Down
81 changes: 47 additions & 34 deletions packages/js/src/ui/context/AppearanceContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,50 @@ export type CSSProperties = {

export type ElementStyles = string | CSSProperties;

export type Elements = {
/**
* Primitive element styles
*/
button?: ElementStyles;
root?: ElementStyles;
bell?: ElementStyles;
bellContainer?: ElementStyles;
popoverContent?: ElementStyles;
popoverTrigger?: ElementStyles;
dropdownContent?: ElementStyles;
dropdownTrigger?: ElementStyles;

/**
* Component element styles
*/
settingsIconContainer?: ElementStyles;
inboxHeader?: ElementStyles;
inboxStatusDropdownTrigger?: ElementStyles;
inboxStatusDropdownContent?: ElementStyles;
inboxStatusDropdownItem?: ElementStyles;
inboxStatusDropdownItemLabel?: ElementStyles;
inboxStatusDropdownItemLabelContainer?: ElementStyles;
inboxStatusDropdownItemLeftIcon?: ElementStyles;
inboxStatusDropdownItemRightIcon?: ElementStyles;
inboxStatusTitle?: ElementStyles;
moreActionsContainer?: ElementStyles;
moreActionsDropdownTrigger?: ElementStyles;
moreActionsDropdownContent?: ElementStyles;
moreActionsDropdownItem?: ElementStyles;
moreActionsDropdownItemLabel?: ElementStyles;
moreActionsDropdownItemLabelContainer?: ElementStyles;
moreActionsDropdownItemLeftIcon?: ElementStyles;
};
/*
* The double underscore signals that entire key extends the right part of the key
* i.e. foo__bar means that foo_bar is an extension of bar. Both keys will be applied when foo_bar is used
* meaning you would have `bar foo__bar` in the dom
*/
export const appearanceKeys = [
//Primitives
'button',
'popoverContent',
'popoverTrigger',
'dropdownContent',
'dropdownTrigger',
'dropdownItem',
'dropdownItemLabel',
'dropdownItemLabelContainer',
'dropdownItemLeftIcon',
'dropdownItemRightIcon',

//General
'root',
'bellIcon',
'bellContainer',
'settings__button',
'inboxHeader',

//Inbox status
'inboxStatus__title',
'inboxStatus__dropdownTrigger',
'inboxStatus__dropdownContent',
'inboxStatus__dropdownItem',
'inboxStatus__dropdownItemLabel',
'inboxStatus__dropdownItemLabelContainer',
'inboxStatus__dropdownItemLeftIcon',
'inboxStatus__dropdownItemRightIcon',

//More actions
'moreActionsContainer',
'moreActions__dropdownTrigger',
'moreActions__dropdownContent',
'moreActions__dropdownItem',
'moreActions__dropdownItemLabel',
'moreActions__dropdownItemLabelContainer',
'moreActions__dropdownItemLeftIcon',
] as const;

export type Variables = {
colorBackground?: string;
Expand All @@ -65,6 +75,9 @@ export type Variables = {
borderRadius?: string;
};

export type AppearanceKey = (typeof appearanceKeys)[number];
export type Elements = Partial<Record<AppearanceKey, ElementStyles>>;

type AppearanceContextType = {
variables?: Variables;
elements?: Elements;
Expand Down
49 changes: 49 additions & 0 deletions packages/js/src/ui/helpers/useStyle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { createMemo, createSignal, onMount } from 'solid-js';
import { AppearanceKey, appearanceKeys, Elements, useAppearance } from '../context';
import { cn } from './utils';

export const useStyle = () => {
const appearance = useAppearance();
const [isServer, setIsServer] = createSignal(true);

onMount(() => {
setIsServer(false);
});

const styleFuncMemo = createMemo(() => (appearanceKey: AppearanceKey, className?: string) => {
const appearanceClassname =
typeof appearance.elements?.[appearanceKey] === 'string'
? (appearance.elements?.[appearanceKey] as string) || ''
: '';

const appearanceKeyParts = appearanceKey.split('__');
const finalAppearanceKeys: (keyof Elements)[] = [];
for (let i = 0; i < appearanceKeyParts.length; i++) {
const accumulated = appearanceKeyParts.slice(i).join('__');
if (appearanceKeys.includes(accumulated as keyof Elements)) {
finalAppearanceKeys.push(accumulated as keyof Elements);
}
}
//Have keys with least amount of `__` first, i.e. have `bar foo__bar` in the DOM.
finalAppearanceKeys.sort((a, b) => {
const countA = (a.match(/__/g) || []).length;
const countB = (b.match(/__/g) || []).length;

return countA - countB;
});

const cssInJsClasses =
!!finalAppearanceKeys.length && !isServer()
? finalAppearanceKeys.map((appKey) => appearance.appearanceKeyToCssInJsClass[appKey])
: [];

return cn(
...finalAppearanceKeys,
className, // default styles
appearanceClassname, // overrides via appearance prop classes
...cssInJsClasses
);
});

return styleFuncMemo();
};
36 changes: 0 additions & 36 deletions packages/js/src/ui/helpers/useStyle.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion packages/js/src/ui/icons/BellIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function BellIcon() {
height="20"
fill="none"
viewBox="0 0 20 20"
class={style('bell')}
class={style('bellIcon')}
>
<path
fill="currentColor"
Expand Down
2 changes: 1 addition & 1 deletion packages/js/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,5 @@ export default defineConfig((config: Options) => {
}),
],
};
return runAfterLast([copyPackageJson('esm'), copyPackageJson('cjs')])(umd, esm, cjs);
return runAfterLast([copyPackageJson('esm'), copyPackageJson('cjs'), 'tsc --noEmit'])(umd, esm, cjs);
});
7 changes: 0 additions & 7 deletions playground/nextjs/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ export default function Home() {
console.log('mounting', ui);
ui.mountInbox(el);

setTimeout(() => {
ui.updateAppearance({
baseTheme: [{ variables: { colorForeground: 'blue', colorNeutral: 'white', colorBackground: 'black' } }],
variables: { colorPrimary: 'purple' },
});
}, 5000);

return () => {
ui.unmountComponent(el);
};
Expand Down
Loading

0 comments on commit 5cb46a1

Please sign in to comment.