@storybook/nextjs 7.0.0-beta.12 → 7.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,10 @@
15
15
  - [Local Images](#local-images)
16
16
  - [Remote Images](#remote-images)
17
17
  - [AVIF](#avif)
18
+ - [Next.js Font Optimization](#nextjs-font-optimization)
19
+ - [@next/font/google](#nextfontgoogle)
20
+ - [@next/font/local](#nextfontlocal)
21
+ - [Not supported features of @next/font](#not-supported-features-of-nextfont)
18
22
  - [Next.js Routing](#nextjs-routing)
19
23
  - [Overriding defaults](#overriding-defaults)
20
24
  - [Global Defaults](#global-defaults)
@@ -24,6 +28,7 @@
24
28
  - [Set `nextjs.appDirectory` to `true`](#set-nextjsappdirectory-to-true)
25
29
  - [Overriding defaults](#overriding-defaults-1)
26
30
  - [Global Defaults](#global-defaults-1)
31
+ - [`useSelectedLayoutSegment` and `useSelectedLayoutSegments` hook](#useselectedlayoutsegment-and-useselectedlayoutsegments-hook)
27
32
  - [Default Navigation Context](#default-navigation-context)
28
33
  - [Actions Integration Caveats](#actions-integration-caveats-1)
29
34
  - [Sass/Scss](#sassscss)
@@ -45,6 +50,8 @@
45
50
 
46
51
  👉 [Next.js's Image Component](#nextjss-image-component)
47
52
 
53
+ 👉 [Next.js Font Optimization](#nextjs-font-optimization)
54
+
48
55
  👉 [Next.js Routing (next/router)](#nextjs-routing)
49
56
 
50
57
  👉 [Next.js Navigation (next/navigation)](#nextjs-navigation)
@@ -208,6 +215,54 @@ export default function Home() {
208
215
 
209
216
  This format is not supported by this framework yet. Feel free to [open up an issue](https://github.com/storybookjs/storybook/issues) if this is something you want to see.
210
217
 
218
+ ### Next.js Font Optimization
219
+
220
+ [@next/font](https://nextjs.org/docs/basic-features/font-optimization) is partially supported in Storybook. The packages `@next/font/google` and `@next/font/local` are supported.
221
+
222
+ #### @next/font/google
223
+
224
+ You don't have to do anything. `@next/font/google` is supported out of the box.
225
+
226
+ #### @next/font/local
227
+
228
+ For local fonts you have to define the [src](https://nextjs.org/docs/api-reference/next/font#src) property.
229
+ The path is relative to the directory where the font loader function is called.
230
+
231
+ If the following component defines your localFont like this:
232
+
233
+ ```js
234
+ // src/components/MyComponent.js
235
+ import localFont from '@next/font/local';
236
+
237
+ const localRubikStorm = localFont({ src: './fonts/RubikStorm-Regular.ttf' });
238
+ ```
239
+
240
+ You have to tell Storybook where the `fonts` directory is located. The `from` value is relative to the `.storybook` directory. The `to` value is relative to the execution context of Storybook. Very likely it is the root of your project.
241
+
242
+ ```js
243
+ // .storybook/main.js
244
+ module.exports = {
245
+ ...
246
+ "staticDirs": [
247
+ {
248
+ from: '../src/components/fonts',
249
+ to: 'src/components/fonts'
250
+ }
251
+ ],
252
+ }
253
+ ```
254
+
255
+ #### Not supported features of @next/font
256
+
257
+ The following features are not supported (yet). Support for these features might be planned for the future:
258
+
259
+ - [Support font loaders configuration in next.config.js](https://nextjs.org/docs/basic-features/font-optimization#specifying-a-subset)
260
+ - [fallback](https://nextjs.org/docs/api-reference/next/font#fallback) option
261
+ - [adjustFontFallback](https://nextjs.org/docs/api-reference/next/font#adjustfontfallback) option
262
+ - [declarations](https://nextjs.org/docs/api-reference/next/font#declarations) option
263
+ - [preload](https://nextjs.org/docs/api-reference/next/font#preload) option gets ignored. Storybook handles Font loading its own way.
264
+ - [display](https://nextjs.org/docs/api-reference/next/font#display) option gets ignored. All fonts are loaded with display set to "block" to make Storybook load the font properly.
265
+
211
266
  ### Next.js Routing
212
267
 
213
268
  [Next.js's router](https://nextjs.org/docs/routing/introduction) is automatically stubbed for you so that when the router is interacted with, all of its interactions are automatically logged to the Actions ctions panel if you have the [Storybook actions addon](https://storybook.js.org/docs/react/essentials/actions).
@@ -440,6 +495,40 @@ export const parameters = {
440
495
  };
441
496
  ```
442
497
 
498
+ #### `useSelectedLayoutSegment` and `useSelectedLayoutSegments` hook
499
+
500
+ The `useSelectedLayoutSegment` and `useSelectedLayoutSegments` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments you want to use.
501
+
502
+ ```js
503
+ // SomeComponentThatUsesTheNavigation.stories.js
504
+ import SomeComponentThatUsesTheNavigation from './SomeComponentThatUsesTheNavigation';
505
+
506
+ export default {
507
+ component: SomeComponentThatUsesTheNavigation,
508
+ parameters: {
509
+ nextjs: {
510
+ appDirectory: true,
511
+ navigation: {
512
+ segments: ['dashboard', 'analytics']
513
+ },
514
+ },
515
+ },
516
+ };
517
+
518
+ export const Example = {};
519
+
520
+ // SomeComponentThatUsesTheNavigation.js
521
+ import { useSelectedLayoutSegment, useSelectedLayoutSegments } from 'next/navigation';
522
+
523
+ export default function SomeComponentThatUsesTheNavigation() {
524
+ const segment = useSelectedLayoutSegment(); // dashboard
525
+ const segments = useSelectedLayoutSegments(); // ["dashboard", "analytics"]
526
+ ...
527
+ }
528
+ ```
529
+
530
+ The default value of `nextjs.navigation.segments` is `[]` if not set.
531
+
443
532
  #### Default Navigation Context
444
533
 
445
534
  The default values on the stubbed navigation context are as follows:
@@ -0,0 +1 @@
1
+ import"./chunk-4MG4OZFL.mjs";import React from"react";import{AppRouterContext,LayoutRouterContext}from"next/dist/shared/lib/app-router-context";import{PathnameContext,SearchParamsContext}from"next/dist/shared/lib/hooks-client-context";var getParallelRoutes=segmentsList=>{let segment=segmentsList.shift();return segment?[segment,{children:getParallelRoutes(segmentsList)}]:[]},AppRouterProvider=({children,action,routeParams})=>{let{pathname,query,segments=[],...restRouteParams}=routeParams;return React.createElement(AppRouterContext.Provider,{value:{push(...args){action("nextNavigation.push")(...args)},replace(...args){action("nextNavigation.replace")(...args)},forward(...args){action("nextNavigation.forward")(...args)},back(...args){action("nextNavigation.back")(...args)},prefetch(...args){action("nextNavigation.prefetch")(...args)},refresh:()=>{action("nextNavigation.refresh")()},...restRouteParams}},React.createElement(SearchParamsContext.Provider,{value:new URLSearchParams(query)},React.createElement(LayoutRouterContext.Provider,{value:{childNodes:new Map,tree:[pathname,{children:getParallelRoutes([...segments])}],url:pathname}},React.createElement(PathnameContext.Provider,{value:pathname},children))))},app_router_provider_default=AppRouterProvider;export{app_router_provider_default as default};
@@ -0,0 +1,3 @@
1
+ declare function storybookNextjsFontLoader(this: any): Promise<string>;
2
+
3
+ export { storybookNextjsFontLoader as default };
@@ -0,0 +1,40 @@
1
+ "use strict";var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod)),__toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var storybook_nextjs_font_loader_exports={};__export(storybook_nextjs_font_loader_exports,{default:()=>storybookNextjsFontLoader});module.exports=__toCommonJS(storybook_nextjs_font_loader_exports);var import_loader_utils3=__toESM(require("next/dist/compiled/loader-utils3")),import_utils=require("@next/font/dist/google/utils"),cssCache=new Map;async function getFontFaceDeclarations(options){let{fontFamily,weights,styles,selectedVariableAxes,display,variable}=(0,import_utils.validateData)(options.fontFamily,[options.props]),fontAxes=(0,import_utils.getFontAxes)(fontFamily,weights,styles,selectedVariableAxes),url=(0,import_utils.getUrl)(fontFamily,fontAxes,display);try{let hasCachedCSS=cssCache.has(url),fontFaceCSS=hasCachedCSS?cssCache.get(url):await(0,import_utils.fetchCSSFromGoogleFonts)(url,fontFamily).catch(()=>null);if(hasCachedCSS?cssCache.delete(url):cssCache.set(url,fontFaceCSS),fontFaceCSS===null)throw Error(`Failed to fetch \`${fontFamily}\` from Google Fonts.`);return{id:import_loader_utils3.default.getHashDigest(url,"md5","hex",6),fontFamily,fontFaceCSS,weights,styles,variable}}catch{throw new Error("Google Fonts couldn't be loaded.")}}var import_loader_utils32=__toESM(require("next/dist/compiled/loader-utils3")),import_utils2=require("@next/font/dist/local/utils"),import_path=__toESM(require("path"));async function getFontFaceDeclarations2(options,rootContext){let localFontSrc=options.props.src,parentFolder=options.filename.split("/").slice(0,-1).join("/").replace(rootContext,""),{weight,style,variable}=(0,import_utils2.validateData)("",options.props),id=`font-${import_loader_utils32.default.getHashDigest(Buffer.from(JSON.stringify(localFontSrc)),"md5","hex",6)}`;return{id,fontFamily:id,fontFaceCSS:(()=>{if(typeof localFontSrc=="string"){let localFontPath=import_path.default.join(parentFolder,localFontSrc);return`@font-face {
2
+ font-family: ${id};
3
+ src: url(${localFontPath});
4
+ }`}return localFontSrc.map(font=>{let localFontPath=import_path.default.join(parentFolder,font.path);return`@font-face {
5
+ font-family: ${id};
6
+ src: url(${localFontPath});
7
+ ${font.weight?`font-weight: ${font.weight};`:""}
8
+ ${font.style?`font-style: ${font.style};`:""}
9
+ }`}).join("")})(),weights:weight?[weight]:[],styles:style?[style]:[],variable}}function getCSSMeta(options){let className=getClassName(options),style=getStylesObj(options),variableClassName=`__variable_${className}`,classNamesCSS=`
10
+ .${className} {
11
+ font-family: ${options.fontFamily};
12
+ ${isNextCSSPropertyValid(options.styles)?`font-style: ${options.styles[0]};`:""}
13
+ ${isNextCSSPropertyValid(options.weights)?`font-weight: ${options.weights[0]};`:""}
14
+ }
15
+
16
+ ${options.variable?`.${variableClassName} { ${options.variable}: '${options.fontFamily}'; }`:""}
17
+ `,fontFaceCSS=`${changeFontDisplayToSwap(options.fontFaceCSS)}`;return{className,fontFaceCSS,classNamesCSS,style,...options.variable?{variableClassName}:{}}}function getClassName({styles,weights,fontFamily}){let font=fontFamily.replace(" ","-").toLowerCase(),style=isNextCSSPropertyValid(styles)?styles[0]:null,weight=isNextCSSPropertyValid(weights)?weights[0]:null;return`${font}${style?`-${style}`:""}${weight?`-${weight}`:""}`}function getStylesObj({styles,weights,fontFamily}){return{fontFamily,...isNextCSSPropertyValid(styles)?{fontStyle:styles[0]}:{},...isNextCSSPropertyValid(weights)?{fontWeight:weights[0]}:{}}}function isNextCSSPropertyValid(prop){return prop.length===1&&prop[0]!=="variable"}function changeFontDisplayToSwap(css){return css.replaceAll("font-display: optional;","font-display: block;")}function setFontDeclarationsInHead({id,fontFaceCSS,classNamesCSS}){return`
18
+ if (!document.getElementById('id-${id}')) {
19
+ const fontDeclarations = \`${fontFaceCSS}\`;
20
+ const style = document.createElement('style');
21
+ style.setAttribute('id', 'font-face-${id}');
22
+ style.innerHTML = fontDeclarations;
23
+ document.head.appendChild(style);
24
+
25
+ const classNamesCSS = \`${classNamesCSS}\`;
26
+ const classNamesStyle = document.createElement('style');
27
+ classNamesStyle.setAttribute('id', 'classnames-${id}');
28
+ classNamesStyle.innerHTML = classNamesCSS;
29
+ document.head.appendChild(classNamesStyle);
30
+
31
+ }
32
+ `}async function storybookNextjsFontLoader(){let options=this.getOptions(),rootCtx=this.rootContext,fontFaceDeclaration;if(options.source==="@next/font/google"&&(fontFaceDeclaration=await getFontFaceDeclarations(options)),options.source==="@next/font/local"&&(fontFaceDeclaration=await getFontFaceDeclarations2(options,rootCtx)),typeof fontFaceDeclaration<"u"){let cssMeta=getCSSMeta(fontFaceDeclaration);return`
33
+ ${setFontDeclarationsInHead({fontFaceCSS:cssMeta.fontFaceCSS,id:fontFaceDeclaration.id,classNamesCSS:cssMeta.classNamesCSS})}
34
+
35
+ module.exports = {
36
+ className: "${cssMeta.className}",
37
+ style: ${JSON.stringify(cssMeta.style)}
38
+ ${cssMeta.variableClassName?`, variable: "${cssMeta.variableClassName}"`:""}
39
+ }
40
+ `}return"module.exports = {}"}0&&(module.exports={});
@@ -0,0 +1,40 @@
1
+ import"../../../chunk-4MG4OZFL.mjs";import loaderUtils from"next/dist/compiled/loader-utils3";import{fetchCSSFromGoogleFonts,getFontAxes,getUrl,validateData}from"@next/font/dist/google/utils";var cssCache=new Map;async function getFontFaceDeclarations(options){let{fontFamily,weights,styles,selectedVariableAxes,display,variable}=validateData(options.fontFamily,[options.props]),fontAxes=getFontAxes(fontFamily,weights,styles,selectedVariableAxes),url=getUrl(fontFamily,fontAxes,display);try{let hasCachedCSS=cssCache.has(url),fontFaceCSS=hasCachedCSS?cssCache.get(url):await fetchCSSFromGoogleFonts(url,fontFamily).catch(()=>null);if(hasCachedCSS?cssCache.delete(url):cssCache.set(url,fontFaceCSS),fontFaceCSS===null)throw Error(`Failed to fetch \`${fontFamily}\` from Google Fonts.`);return{id:loaderUtils.getHashDigest(url,"md5","hex",6),fontFamily,fontFaceCSS,weights,styles,variable}}catch{throw new Error("Google Fonts couldn't be loaded.")}}import loaderUtils2 from"next/dist/compiled/loader-utils3";import{validateData as validateData2}from"@next/font/dist/local/utils";import path from"path";async function getFontFaceDeclarations2(options,rootContext){let localFontSrc=options.props.src,parentFolder=options.filename.split("/").slice(0,-1).join("/").replace(rootContext,""),{weight,style,variable}=validateData2("",options.props),id=`font-${loaderUtils2.getHashDigest(Buffer.from(JSON.stringify(localFontSrc)),"md5","hex",6)}`;return{id,fontFamily:id,fontFaceCSS:(()=>{if(typeof localFontSrc=="string"){let localFontPath=path.join(parentFolder,localFontSrc);return`@font-face {
2
+ font-family: ${id};
3
+ src: url(${localFontPath});
4
+ }`}return localFontSrc.map(font=>{let localFontPath=path.join(parentFolder,font.path);return`@font-face {
5
+ font-family: ${id};
6
+ src: url(${localFontPath});
7
+ ${font.weight?`font-weight: ${font.weight};`:""}
8
+ ${font.style?`font-style: ${font.style};`:""}
9
+ }`}).join("")})(),weights:weight?[weight]:[],styles:style?[style]:[],variable}}function getCSSMeta(options){let className=getClassName(options),style=getStylesObj(options),variableClassName=`__variable_${className}`,classNamesCSS=`
10
+ .${className} {
11
+ font-family: ${options.fontFamily};
12
+ ${isNextCSSPropertyValid(options.styles)?`font-style: ${options.styles[0]};`:""}
13
+ ${isNextCSSPropertyValid(options.weights)?`font-weight: ${options.weights[0]};`:""}
14
+ }
15
+
16
+ ${options.variable?`.${variableClassName} { ${options.variable}: '${options.fontFamily}'; }`:""}
17
+ `,fontFaceCSS=`${changeFontDisplayToSwap(options.fontFaceCSS)}`;return{className,fontFaceCSS,classNamesCSS,style,...options.variable?{variableClassName}:{}}}function getClassName({styles,weights,fontFamily}){let font=fontFamily.replace(" ","-").toLowerCase(),style=isNextCSSPropertyValid(styles)?styles[0]:null,weight=isNextCSSPropertyValid(weights)?weights[0]:null;return`${font}${style?`-${style}`:""}${weight?`-${weight}`:""}`}function getStylesObj({styles,weights,fontFamily}){return{fontFamily,...isNextCSSPropertyValid(styles)?{fontStyle:styles[0]}:{},...isNextCSSPropertyValid(weights)?{fontWeight:weights[0]}:{}}}function isNextCSSPropertyValid(prop){return prop.length===1&&prop[0]!=="variable"}function changeFontDisplayToSwap(css){return css.replaceAll("font-display: optional;","font-display: block;")}function setFontDeclarationsInHead({id,fontFaceCSS,classNamesCSS}){return`
18
+ if (!document.getElementById('id-${id}')) {
19
+ const fontDeclarations = \`${fontFaceCSS}\`;
20
+ const style = document.createElement('style');
21
+ style.setAttribute('id', 'font-face-${id}');
22
+ style.innerHTML = fontDeclarations;
23
+ document.head.appendChild(style);
24
+
25
+ const classNamesCSS = \`${classNamesCSS}\`;
26
+ const classNamesStyle = document.createElement('style');
27
+ classNamesStyle.setAttribute('id', 'classnames-${id}');
28
+ classNamesStyle.innerHTML = classNamesCSS;
29
+ document.head.appendChild(classNamesStyle);
30
+
31
+ }
32
+ `}async function storybookNextjsFontLoader(){let options=this.getOptions(),rootCtx=this.rootContext,fontFaceDeclaration;if(options.source==="@next/font/google"&&(fontFaceDeclaration=await getFontFaceDeclarations(options)),options.source==="@next/font/local"&&(fontFaceDeclaration=await getFontFaceDeclarations2(options,rootCtx)),typeof fontFaceDeclaration<"u"){let cssMeta=getCSSMeta(fontFaceDeclaration);return`
33
+ ${setFontDeclarationsInHead({fontFaceCSS:cssMeta.fontFaceCSS,id:fontFaceDeclaration.id,classNamesCSS:cssMeta.classNamesCSS})}
34
+
35
+ module.exports = {
36
+ className: "${cssMeta.className}",
37
+ style: ${JSON.stringify(cssMeta.style)}
38
+ ${cssMeta.variableClassName?`, variable: "${cssMeta.variableClassName}"`:""}
39
+ }
40
+ `}return"module.exports = {}"}export{storybookNextjsFontLoader as default};