Skip to content

Commit

Permalink
feat!: add uikit plugin instead of theme render props
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS committed Mar 20, 2024
1 parent f99b4ff commit 7988288
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 30 deletions.
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ interface RenderParams<Data, Plugins> {
lang?: string;
isMobile?: boolean;

// html attributes
htmlAttributes?: string;
// header tag content
// meta tags
meta?: Meta[];
Expand All @@ -67,10 +69,10 @@ interface RenderParams<Data, Plugins> {

// content of body tag
bodyContent?: {
// initial application theme if @gravity-ui/uikit is used
theme?: string;
// class name for body tag
className?: string;
// body attributes
attributes?: string;
// body content before div tag with id root
beforeRoot?: string;
// innerHtml content of div tag with id root
Expand Down Expand Up @@ -422,6 +424,43 @@ export interface LayoutOptions {
}
```

### @gravity-ui/ui-kit

Adds body attributes.

Usage:

```js
import {createRenderFunction, createUikitPlugin} from '@gravity-ui/app-layout';

const renderLayout = createRenderFunction([createUikitPlugin()]);

app.get((req, res) => {
res.send(
renderLayout({
title: 'Home page',
pluginsOptions: {
uikit: {
theme: 'dark',
direction: 'ltr',
},
},
}),
);
});
```

Plugin options:

```typescript
interface UikitPluginOptions {
theme: string;
direction?: 'ltr' | 'rtl';
}
```

### Helpers

There is helper to create all plugins:

```js
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export {
createGoogleAnalyticsPlugin,
createYandexMetrikaPlugin,
createLayoutPlugin,
createUikitPlugin,
createDefaultPlugins,
} from './plugins/index.js';

Expand All @@ -31,3 +32,4 @@ export type {
GoogleAnalyticsPluginOptions,
} from './plugins/google-analytics/index.js';
export type {LayoutPluginOptions, Manifest} from './plugins/layout/index.js';
export type {UikitPluginOptions} from './plugins/uikit/index.js';
15 changes: 13 additions & 2 deletions src/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import {createGoogleAnalyticsPlugin} from './google-analytics/index.js';
import {createLayoutPlugin} from './layout/index.js';
import type {LayoutInitOptions} from './layout/index.js';
import {createUikitPlugin} from './uikit/index.js';
import {createYandexMetrikaPlugin} from './yandex-metrika/index.js';

export function createDefaultPlugins({layout}: {layout: LayoutInitOptions}) {
return [createGoogleAnalyticsPlugin(), createYandexMetrikaPlugin(), createLayoutPlugin(layout)];
return [
createGoogleAnalyticsPlugin(),
createYandexMetrikaPlugin(),
createUikitPlugin(),
createLayoutPlugin(layout),
];
}

export {createGoogleAnalyticsPlugin, createYandexMetrikaPlugin, createLayoutPlugin};
export {
createGoogleAnalyticsPlugin,
createYandexMetrikaPlugin,
createLayoutPlugin,
createUikitPlugin,
};
36 changes: 36 additions & 0 deletions src/plugins/uikit/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type {Plugin} from '../../types.js';

import type {UikitPluginOptions} from './types.js';

export type {UikitPluginOptions} from './types.js';

export function createUikitPlugin(): Plugin<UikitPluginOptions, 'uikit'> {
return {
name: 'uikit',
apply({options, renderContent}) {
if (!options) {
return;
}

const {theme, direction} = options;

const cls = renderContent.bodyContent.attributes.class;
const className = Array.from(
new Set([...(cls ? String(cls).split(/\s+/) : []), ...getRootClassName(theme)]),
)
.filter(Boolean)
.join(' ');
renderContent.bodyContent.attributes.class = className;

Check warning on line 23 in src/plugins/uikit/index.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Assignment to property of function parameter 'renderContent'

if (direction === 'rtl') {
renderContent.bodyContent.attributes.dir = 'rtl';

Check warning on line 26 in src/plugins/uikit/index.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Assignment to property of function parameter 'renderContent'
}
},
};
}

function getRootClassName(theme: string) {
const classes = ['g-root'];
classes.push(`g-root_theme_${theme}`);
return classes;
}
4 changes: 4 additions & 0 deletions src/plugins/uikit/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface UikitPluginOptions {
theme: string;
direction?: 'ltr' | 'rtl';
}
17 changes: 12 additions & 5 deletions src/render.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {createUikitPlugin} from './plugins/index.js';
import {createRenderFunction} from './render.js';
import type {Plugin} from './types.js';

Expand Down Expand Up @@ -30,19 +31,25 @@ test('should render body classes', () => {
}),
).toMatch(/<body class="test">\s*<div id="root">\s*content\s*<\/div>\s*<\/body>/);
expect(
createRenderFunction()({
createRenderFunction([createUikitPlugin()])({
title: 'Foobar',
bodyContent: {root: 'content', theme: 'light'},
bodyContent: {root: 'content'},
pluginsOptions: {
uikit: {theme: 'light'},
},
}),
).toMatch(
/<body class="g-root g-root_theme_light">\s*<div id="root">\s*content\s*<\/div>\s*<\/body>/,
);
expect(
createRenderFunction()({
createRenderFunction([createUikitPlugin()])({
title: 'Foobar',
bodyContent: {root: 'content', className: 'test', theme: 'light'},
bodyContent: {root: 'content', className: 'test'},
pluginsOptions: {
uikit: {theme: 'light'},
},
}),
).toMatch(
/<body class="g-root g-root_theme_light test">\s*<div id="root">\s*content\s*<\/div>\s*<\/body>/,
/<body class="test g-root g-root_theme_light">\s*<div id="root">\s*content\s*<\/div>\s*<\/body>/,
);
});
1 change: 0 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ export interface RenderParams<Data, Plugins extends Plugin[] = []> extends Commo
inlineScripts?: string[];
inlineStyleSheets?: string[];
bodyContent?: {
theme?: string;
className?: string;
attributes?: Attributes;
beforeRoot?: string;
Expand Down
21 changes: 1 addition & 20 deletions src/utils/generateRenderContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,6 @@ import type {
} from '../types.js';
import {getRenderHelpers, hasProperty} from '../utils.js';

function getRootClassName(theme?: string) {
if (!theme) {
return [];
}
const classes = ['g-root'];
if (theme) {
classes.push(`g-root_theme_${theme}`);
}
return classes;
}

const defaultIcon: Icon = {
type: 'image/png',
sizes: '16x16',
Expand Down Expand Up @@ -63,17 +52,9 @@ export function generateRenderContent<Plugins extends Plugin[], Data>(
inlineScripts.unshift(`window.__DATA__ = ${htmlescape(params.data || {})};`);

const content = params.bodyContent ?? {};

const {theme, className} = content;
const bodyClassName = Array.from(
new Set([...getRootClassName(theme), ...(className ? className.split(' ') : [])]),
)
.filter(Boolean)
.join(' ');

const bodyContent: BodyContent = {
attributes: {
class: bodyClassName,
class: content.className,
...content.attributes,
},
root: content.root,
Expand Down

0 comments on commit 7988288

Please sign in to comment.