1(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{182:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return c})),n.d(t,"metadata",(function(){return l})),n.d(t,"rightToc",(function(){return s})),n.d(t,"default",(function(){return b}));var o=n(2),a=n(9),i=(n(0),n(227)),r=n(229),c={id:"tutorial",title:"Tutorial"},l={id:"tutorial",isDocsHomePage:!1,title:"Tutorial",description:"This tutorial assumes you've gone through the Getting Started guide to set up Litho. Make sure you set up Litho's core libraries and Sections' libraries.",source:"@site/docs/tutorial.mdx",permalink:"/docs/tutorial",editUrl:"https://github.com/facebook/litho/edit/master/website/docs/tutorial.mdx",sidebar:"mainSidebar",previous:{title:"Getting Started",permalink:"/docs/"},next:{title:"Writing Components",permalink:"/docs/writing-components"}},s=[{value:"1. Hello World",id:"1-hello-world",children:[]},{value:"2. Your First Custom Component",id:"2-your-first-custom-component",children:[]},{value:"3. Creating a List of Items",id:"3-creating-a-list-of-items",children:[]},{value:"4. Defining a Component's properties",id:"4-defining-a-components-properties",children:[]},{value:"Summary",id:"summary",children:[{value:"Looking for more?",id:"looking-for-more",children:[]}]}],p={rightToc:s};function b(e){var t=e.components,n=Object(a.a)(e,["components"]);return Object(i.b)("wrapper",Object(o.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"This tutorial assumes you've gone through the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"getting-started"}),"Getting Started")," guide to set up Litho. Make sure you set up Litho's core libraries and Sections' libraries."),Object(i.b)("p",null,'In this tutorial, you\'ll start by building a basic "Hello World!" screen using Litho and work your way up to creating a list of "Hello World!" items on the screen. Along the way, you\'ll learn about the building blocks of Litho: ',Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/Component.html"}),"Component"),", and ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/LithoView.html"}),"LithoView"),". You will also learn how to create lists with ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/sections/Section.html"}),"Section")," and how to set properties on components."),Object(i.b)("h2",{id:"1-hello-world"},"1. Hello World"),Object(i.b)("p",null,'In this initial step, you\'ll display a view with "Hello World!".'),Object(i.b)("p",null,"First, initialize ",Object(i.b)("inlineCode",{parentName:"p"},"SoLoader")," in your ",Object(i.b)("inlineCode",{parentName:"p"},"Application")," class:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),"public class SampleApplication extends Application {\n\n @Override\n public void onCreate() {\n super.onCreate();\n\n SoLoader.init(this, false);\n }\n}\n")),Object(i.b)("p",null,"Behind the scenes, Litho uses ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://yogalayout.com/docs/"}),"Yoga")," for layout. Yoga has native dependencies and ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/facebook/SoLoader"}),"SoLoader")," is brought in to take care of loading those. Initializing ",Object(i.b)("inlineCode",{parentName:"p"},"SoLoader")," here ensures that you're not referencing unloaded libraries later on."),Object(i.b)("p",null,"Next, add a predefined ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/widget/Text.html"}),"Text")," Litho component to an activity:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),'@Override\npublic void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n final ComponentContext c = new ComponentContext(this);\n\n final Component component = Text.create(c)\n .text("Hello World")\n .textSizeDip(50)\n .build();\n\n setContentView(LithoView.create(c, component));\n}\n')),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"LithoView")," is an Android ",Object(i.b)("inlineCode",{parentName:"p"},"ViewGroup")," that can render components; it is the bridge between Litho components and Android ",Object(i.b)("inlineCode",{parentName:"p"},"View"),"s. The example sets the content for the activity to a ",Object(i.b)("inlineCode",{parentName:"p"},"LithoView")," that displays a ",Object(i.b)("inlineCode",{parentName:"p"},"Text")," component."),Object(i.b)("p",null,"How do the components come into play? Let's zero in on this piece of code:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),'Text.create(c)\n .text("Hello World")\n .textSizeDip(50)\n .build();\n')),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"Text")," is a core component defined in ",Object(i.b)("inlineCode",{parentName:"p"},"com.facebook.litho.widget"),". It has a number of properties such as ",Object(i.b)("em",{parentName:"p"},"text")," and ",Object(i.b)("em",{parentName:"p"},"textSize")," which you can set as shown. These properties are called ",Object(i.b)("em",{parentName:"p"},"props")," as inspired by ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://facebook.github.io/react/"}),"React")," terminology.\nYou'll learn how to write your own components later but it's worth noting the ",Object(i.b)("inlineCode",{parentName:"p"},"Text")," class is generated from a ",Object(i.b)("inlineCode",{parentName:"p"},"TextSpec")," class. The generated component class provides a builder API with methods to define values for the component's props."),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"Text")," component is added as a single child component to the ",Object(i.b)("inlineCode",{parentName:"p"},"LithoView")," in the example. You could instead have a single root component with several child components. You'll see how to do this in later steps."),Object(i.b)("p",null,"That's it! Run the app, you should see something like this:"),Object(i.b)("img",{src:Object(r.a)("/images/barebones1.png"),style:{width:"300px"}}),Object(i.b)("p",null,"Not pretty, but this is certainly a start!"),Object(i.b)("h2",{id:"2-your-first-custom-component"},"2. Your First Custom Component"),Object(i.b)("p",null,"At the end of this tutorial you'll have a simple, scrollable list. This list will just display an item with a title and subtitle a whole lot of times. Exciting times!\nIn this part of the tutorial, you'll write a simple c
1omponent that is the list item. Naturally, a real world app would define a more complicated component but you'll learn all the basics you need to do that in this example."),Object(i.b)("p",null,"Ready? It's time to dive in and build this component. In Litho, you write ",Object(i.b)("em",{parentName:"p"},"Spec")," classes to declare the layout for your components. The framework then generates the underlying component class that you use in your code to create a component instance."),Object(i.b)("p",null,"Your custom component will be called ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," and it will display a title with a smaller subtitle underneath. Therefore, you need to create a class named ",Object(i.b)("inlineCode",{parentName:"p"},"ListItemSpec")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),'@LayoutSpec\npublic class ListItemSpec {\n\n @OnCreateLayout\n static Component onCreateLayout(ComponentContext c) {\n\n return Column.create(c)\n .paddingDip(ALL, 16)\n .backgroundColor(Color.WHITE)\n .child(\n Text.create(c)\n .text("Hello world")\n .textSizeSp(40))\n .child(\n Text.create(c)\n .text("Litho tutorial")\n .textSizeSp(20))\n .build();\n }\n}\n')),Object(i.b)("p",null,"You should recognize the ",Object(i.b)("inlineCode",{parentName:"p"},"Text")," component from the previous tutorial step. In this example, you're passing it in as a ",Object(i.b)("inlineCode",{parentName:"p"},"child")," property of a ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/Column.html"}),"Column"),". You can think of a ",Object(i.b)("inlineCode",{parentName:"p"},"Column")," as equivalent to a ",Object(i.b)("inlineCode",{parentName:"p"},"<div>")," in HTML. It's a wrapper, used mainly for collating things together and perhaps adding some background styling. Since Litho uses ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://yogalayout.com/docs/"}),"Yoga"),", you can add flexbox attributes to set the layout for the children of a ",Object(i.b)("inlineCode",{parentName:"p"},"Column")," or a ",Object(i.b)("inlineCode",{parentName:"p"},"Row"),". Here, you simply set the padding and the background color."),Object(i.b)("p",null,"How do you render this component? In your activity, simply change the ",Object(i.b)("inlineCode",{parentName:"p"},"Component")," definition to:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),"final Component component = ListItem.create(c).build();\n")),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(o.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(o.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(o.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(o.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(o.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"That's ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," you're using, not ",Object(i.b)("inlineCode",{parentName:"p"},"ListItemSpec"),"."))),Object(i.b)("p",null,"Where did ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," come from? Where are ",Object(i.b)("inlineCode",{parentName:"p"},"create")," and ",Object(i.b)("inlineCode",{parentName:"p"},"build")," defined? This is the magic of Litho ",Object(i.b)("em",{parentName:"p"},"Specs"),"."),Object(i.b)("p",null,"In the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"http://fblitho.com/docs/getting-started"}),"Getting Started")," guide, we saw how to add the dependencies to your project to make Litho code generation work.\nThis runs an annotation processor over your co
1de. It looks for ",Object(i.b)("inlineCode",{parentName:"p"},"FooSpec")," class names and generates ",Object(i.b)("inlineCode",{parentName:"p"},"Foo")," classes with the same package as your spec. These classes will have all the methods required by Litho automatically filled in. In addition, based upon the specification, there will be extra methods (such as ",Object(i.b)("inlineCode",{parentName:"p"},"Text"),"'s ",Object(i.b)("inlineCode",{parentName:"p"},".textSizeSp")," or the ",Object(i.b)("inlineCode",{parentName:"p"},".backgroundColor")," method of ",Object(i.b)("inlineCode",{parentName:"p"},"Column"),"/",Object(i.b)("inlineCode",{parentName:"p"},"Row"),") generated by annotation processor."),Object(i.b)("p",null,"It's as simple as that. Run your app. You should see something like this:"),Object(i.b)("img",{src:Object(r.a)("/images/barebones2.png"),width:"300px"}),Object(i.b)("h2",{id:"3-creating-a-list-of-items"},"3. Creating a List of Items"),Object(i.b)("p",null,"You can create lists in Litho by using the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/sections/widget/RecyclerCollectionComponent.html"}),"RecyclerCollectionComponent")," and the Sections library. ",Object(i.b)("inlineCode",{parentName:"p"},"RecyclerCollectionComponent")," is used for creating scrollable units in Litho and it hides some of the complexity of having to work directly with Android's ",Object(i.b)("inlineCode",{parentName:"p"},"RecyclerView")," and ",Object(i.b)("inlineCode",{parentName:"p"},"Adapter")," concepts."),Object(i.b)("p",null,"With the Sections API, you group the items in your list into sections and write ",Object(i.b)("em",{parentName:"p"},"GroupSectionSpec")," classes to declare what each section renders and what data it uses."),Object(i.b)("p",null,"Ready? It's time to build this section. Your custom section will be called ",Object(i.b)("inlineCode",{parentName:"p"},"ListSection")," and it will render ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," components. Create a class named ",Object(i.b)("inlineCode",{parentName:"p"},"ListSectionSpec")," with the following content:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),"@GroupSectionSpec\npublic class ListSectionSpec {\n\n @OnCreateChildren\n static Children onCreateChildren(final SectionContext c) {\n Children.Builder builder = Children.create();\n\n for (int i = 0; i < 32; i++) {\n builder.child(\n SingleComponentSection.create(c)\n .key(String.valueOf(i))\n .component(ListItem.create(c).build()));\n }\n return builder.build();\n }\n}\n")),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"SingleComponentSection")," is a core section defined in ",Object(i.b)("inlineCode",{parentName:"p"},"com.facebook.litho.sections.widget")," that renders a single component. ",Object(i.b)("inlineCode",{parentName:"p"},"ListSectionSpec")," describes a section that has 32 child sections, each of which is responsible for rendering a ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem"),". We can use this section with ",Object(i.b)("inlineCode",{parentName:"p"},"RecyclerCollectionComponent")," to render our list. ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/sections/widget/RecyclerCollectionComponent.html"}),"RecyclerCollectionComponent")," takes a section as a prop and renders a RecyclerView containing whatever UI the section outputs. It also manages updates and changes from the section such as refreshing data and performing tail fetches. We're not using any data fetching here so lets disable PTR (pull to refresh) for this tutorial. In your activity, change the ",Object(i.b)("inlineCode",{parentName:"p"},"component")," definition to:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),"\nfinal Component component =\n RecyclerCollectionComponent.create(c)\n .disablePTR(true)\n .section(ListSection.create(new SectionContext(c)).build())\n .build();\n\n")),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(o.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(o.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(o.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(o.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.
169H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(o.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"That's ",Object(i.b)("inlineCode",{parentName:"p"},"ListSection")," you're using, not ",Object(i.b)("inlineCode",{parentName:"p"},"ListSectionSpec"),"."))),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"ListSectionSpec")," should look familiar to the ",Object(i.b)("inlineCode",{parentName:"p"},"ListItemSpec")," you wrote in the last step! Litho runs annotation processors over your code to find ",Object(i.b)("inlineCode",{parentName:"p"},"ListSectionSpec")," and generates ",Object(i.b)("inlineCode",{parentName:"p"},"ListSection")," just like how it finds ",Object(i.b)("inlineCode",{parentName:"p"},"ListItemSpec")," and generates ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," in the same package as your spec."),Object(i.b)("p",null,"Run the app. You should see a scrollable list of 32 ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," components:"),Object(i.b)("img",{src:Object(r.a)("/images/barebones3.png"),style:{width:"300px"}}),Object(i.b)("h2",{id:"4-defining-a-components-properties"},"4. Defining a Component's properties"),Object(i.b)("p",null,"Lists are no good if they only contain repetitive copies of a single component. In this part, you'll look at ",Object(i.b)("em",{parentName:"p"},"properties")," or props. These are attributes you can set on components to change their behavior or appearance."),Object(i.b)("p",null,"Adding props to a component is very simple. Props are parameters to methods of the component specification, annotated with the ",Object(i.b)("inlineCode",{parentName:"p"},"@Prop")," annotation."),Object(i.b)("p",null,"Modify ",Object(i.b)("inlineCode",{parentName:"p"},"ListItemSpec")," as follows:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),"@OnCreateLayout\nstatic Component onCreateLayout(\n ComponentContext c,\n @Prop int color,\n @Prop String title,\n @Prop String subtitle) {\n\n return Column.create(c)\n .paddingDip(ALL, 16)\n .backgroundColor(color)\n .child(\n Text.create(c)\n .text(title)\n .textSizeSp(40))\n .child(\n Text.create(c)\n .text(subtitle)\n .textSizeSp(20))\n .build();\n}\n")),Object(i.b)("p",null,"This adds three props: ",Object(i.b)("inlineCode",{parentName:"p"},"title"),", ",Object(i.b)("inlineCode",{parentName:"p"},"subtitle")," and ",Object(i.b)("inlineCode",{parentName:"p"},"color")," props. Notice that the background color and the strings for the ",Object(i.b)("inlineCode",{parentName:"p"},"Text")," components' text are no longer hard-coded and are now based on the ",Object(i.b)("inlineCode",{parentName:"p"},"onCreateLayout")," method parameters."),Object(i.b)("p",null,"The magic happens in the ",Object(i.b)("inlineCode",{parentName:"p"},"@Prop")," annotations and the annotation processor. The processor generates methods on the component builder that correspond to the props in a smart way. You can now change ",Object(i.b)("inlineCode",{parentName:"p"},"ListSectionSpec")," to specify properties when constructing ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem"),":"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),'@OnCreateChildren\nstatic Children onCreateChildren(final SectionContext c) {\n Children.Builder builder = Children.create();\n\n for (int i = 0; i < 32; i++) {\n builder.child(\n SingleComponentSection.create(c)\n .key(String.valueOf(i))\n .component(ListItem.create(c)\n .color(i % 2 == 0 ? Color.WHITE : Color.LTGRAY)\n .title(i + ". Hello, world!")\n .subtitle("Litho tutorial")\n .build()));\n }\n return builder.build();\n}\n')),Object(i.b)("p",null,"Now when ",Object(i.b)("inlineCode",{parentName:"p"},"ListItem")," is constructed, the ",Object(i.b)("inlineCode",{parentName:"p"},"color"),", ",Object(i.b)("inlineCode",{parentName:"p"},"title")," and ",Object(i.b)("inlineCode",{parentName:"p"},"subtitle")," props are passed in with the background color alternating for each row."),Object(i.b)("p",null,"Run the app. You should see something like this:"),Object(i.b)("img",{src:Object(r.a)("/images/barebones4.png"),width:"300px"}
1),Object(i.b)("p",null,"You can specify more options to the ",Object(i.b)("inlineCode",{parentName:"p"},"@Prop")," annotation. For example, consider the property:"),Object(i.b)("pre",null,Object(i.b)("code",Object(o.a)({parentName:"pre"},{className:"language-java"}),"@Prop(optional = true, resType = ResType.DIMEN_OFFSET) int shadowRadius,\n")),Object(i.b)("p",null,"This tells the annotation processor to construct a number of functions, such as ",Object(i.b)("inlineCode",{parentName:"p"},"shadowRadiusPx"),", ",Object(i.b)("inlineCode",{parentName:"p"},"shadowRadiusDip"),", ",Object(i.b)("inlineCode",{parentName:"p"},"shadowRadiusSp")," as well as ",Object(i.b)("inlineCode",{parentName:"p"},"shadowRadiusRes"),"."),Object(i.b)("h2",{id:"summary"},"Summary"),Object(i.b)("p",null,"Congratulations on completing this tutorial! This basic tutorial should arm you with all the building blocks to start using Litho and building your own components. You can find the predefined widget components you can use in the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/widget/package-frame.html"}),"com.facebook.litho.widgets")," and ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"/javadoc/com/facebook/litho/sections/widget/package-frame.html"}),"com.facebook.litho.sections.widget")," packages.\nYou can find the ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/facebook/litho/tree/master/sample-barebones"}),"completed tutorial here"),". Be sure to check out ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"https://github.com/facebook/litho/tree/master/sample"}),"this sample")," for more in-depth code as well as the Litho API documentation."),Object(i.b)("h3",{id:"looking-for-more"},"Looking for more?"),Object(i.b)("p",null,"We briefly talked about Sections in this tutorial when building the list. The Sections framework makes it easy to build complex lists in a declarative, composable way. Learn more in an optional part 2 of this tutorial ",Object(i.b)("a",Object(o.a)({parentName:"p"},{href:"sections-tutorial"}),"here"),"."))}b.isMDXComponent=!0},227:function(e,t,n){"use strict";n.d(t,"a",(function(){return b})),n.d(t,"b",(function(){return u}));var o=n(0),a=n.n(o);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function c(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},i=Object.keys(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)n=i[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=a.a.createContext({}),p=function(e){var t=a.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},b=function(e){var t=p(e.components);return a.a.createElement(s.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.a.createElement(a.a.Fragment,{},t)}},m=a.a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,r=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),b=p(n),m=o,u=b["".concat(r,".").concat(m)]||b[m]||d[m]||i;return n?a.a.createElement(u,c(c({ref:t},s),{},{components:n})):a.a.createElement(u,c({ref:t},s))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c.mdxType="string"==typeof e?e:o,r[1]=c;for(var s=2;s<i;s++)r[s]=n[s];return a.a.createElement.apply(null,r)}return a.a.createElement.apply(null,n)}
1m.displayName="MDXCreateElement"},228:function(e,t,n){"use strict";var o=n(0),a=n(52);t.a=function(){return Object(o.useContext)(a.a)}},229:function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));n(75);var o=n(228),a=n(230);function i(e,t){var n=void 0===t?{}:t,i=n.forcePrependBaseUrl,r=void 0!==i&&i,c=n.absolute,l=void 0!==c&&c,s=Object(o.a)().siteConfig,p=(s=void 0===s?{}:s).baseUrl,b=void 0===p?"/":p,d=s.url;if(!e)return e;if(r)return b+e;if(!Object(a.a)(e))return e;var m=b+e.replace(/^\//,"");return l?d+m:m}},230:function(e,t,n){"use strict";function o(e){return!1===/^(https?:|\/\/|mailto:|tel:)/.test(e)}n.d(t,"a",(function(){return o}))}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.