diff --git a/.clintonrc.json b/.clintonrc.json
index a71b01b..0b8124c 100644
--- a/.clintonrc.json
+++ b/.clintonrc.json
@@ -4,7 +4,7 @@
"tmp/**",
"src/**",
"lib/**",
- "examples/**",
+ "docs-src/**",
"docs/**",
".idea/**",
"*.{html,jpg}",
diff --git a/.npmignore b/.npmignore
index 3379ca7..533259d 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,6 +1,6 @@
node_modules
coverage
-examples
+docs-src
docs
test
.gitignore
diff --git a/examples/src/components/btn-link.html b/docs-src/components/btn-link.html
similarity index 100%
rename from examples/src/components/btn-link.html
rename to docs-src/components/btn-link.html
diff --git a/examples/src/components/button.html b/docs-src/components/button.html
similarity index 100%
rename from examples/src/components/button.html
rename to docs-src/components/button.html
diff --git a/examples/src/components/modal/body.html b/docs-src/components/modal/body.html
similarity index 100%
rename from examples/src/components/modal/body.html
rename to docs-src/components/modal/body.html
diff --git a/examples/src/components/modal/footer.html b/docs-src/components/modal/footer.html
similarity index 100%
rename from examples/src/components/modal/footer.html
rename to docs-src/components/modal/footer.html
diff --git a/examples/src/components/modal/header.html b/docs-src/components/modal/header.html
similarity index 100%
rename from examples/src/components/modal/header.html
rename to docs-src/components/modal/header.html
diff --git a/examples/src/components/modal/index.html b/docs-src/components/modal/index.html
similarity index 100%
rename from examples/src/components/modal/index.html
rename to docs-src/components/modal/index.html
diff --git a/examples/src/components/nav-link.html b/docs-src/components/nav-link.html
similarity index 100%
rename from examples/src/components/nav-link.html
rename to docs-src/components/nav-link.html
diff --git a/examples/src/components/test/child-parent.html b/docs-src/components/test/child-parent.html
similarity index 100%
rename from examples/src/components/test/child-parent.html
rename to docs-src/components/test/child-parent.html
diff --git a/examples/src/components/test/child.html b/docs-src/components/test/child.html
similarity index 100%
rename from examples/src/components/test/child.html
rename to docs-src/components/test/child.html
diff --git a/examples/src/components/test/child2.html b/docs-src/components/test/child2.html
similarity index 100%
rename from examples/src/components/test/child2.html
rename to docs-src/components/test/child2.html
diff --git a/examples/src/components/test/index.html b/docs-src/components/test/index.html
similarity index 100%
rename from examples/src/components/test/index.html
rename to docs-src/components/test/index.html
diff --git a/examples/src/components/test/parent.html b/docs-src/components/test/parent.html
similarity index 100%
rename from examples/src/components/test/parent.html
rename to docs-src/components/test/parent.html
diff --git a/examples/src/components/test/parent2-child2.html b/docs-src/components/test/parent2-child2.html
similarity index 100%
rename from examples/src/components/test/parent2-child2.html
rename to docs-src/components/test/parent2-child2.html
diff --git a/examples/src/components/test/parent2.html b/docs-src/components/test/parent2.html
similarity index 100%
rename from examples/src/components/test/parent2.html
rename to docs-src/components/test/parent2.html
diff --git a/examples/index.js b/docs-src/index.js
similarity index 92%
rename from examples/index.js
rename to docs-src/index.js
index 6898658..bd17e1c 100644
--- a/examples/index.js
+++ b/docs-src/index.js
@@ -9,14 +9,13 @@ const markdownItToc = require('markdown-it-toc-done-right');
// const {render} = require('posthtml-render');
// const hljs = require('highlight.js');
-const src = './examples/src/pages/';
-const dist = './examples/dist/';
-const md = './examples/src/md';
-const docs = './docs/';
+const src = './docs-src/pages/';
+const dist = './docs/';
+const md = './docs-src/md';
const plugins = [
components({
- root: './examples/src',
+ root: './docs-src',
folders: ['components', 'layouts'],
strict: true,
expressions: {
@@ -74,7 +73,6 @@ readdirSync(src).forEach(file => {
.process(html, options)
.then(result => {
writeFileSync(path.resolve(`${dist}${file}`), result.html, 'utf-8');
- writeFileSync(path.resolve(`${docs}${file}`), result.html, 'utf-8');
});
});
diff --git a/examples/src/layouts/body.html b/docs-src/layouts/body.html
similarity index 100%
rename from examples/src/layouts/body.html
rename to docs-src/layouts/body.html
diff --git a/examples/src/layouts/footer.html b/docs-src/layouts/footer.html
similarity index 100%
rename from examples/src/layouts/footer.html
rename to docs-src/layouts/footer.html
diff --git a/examples/src/layouts/header.html b/docs-src/layouts/header.html
similarity index 100%
rename from examples/src/layouts/header.html
rename to docs-src/layouts/header.html
diff --git a/examples/src/layouts/html.html b/docs-src/layouts/html.html
similarity index 100%
rename from examples/src/layouts/html.html
rename to docs-src/layouts/html.html
diff --git a/examples/src/layouts/page.html b/docs-src/layouts/page.html
similarity index 100%
rename from examples/src/layouts/page.html
rename to docs-src/layouts/page.html
diff --git a/examples/src/md/changelog.md b/docs-src/md/changelog.md
similarity index 100%
rename from examples/src/md/changelog.md
rename to docs-src/md/changelog.md
diff --git a/examples/src/md/introduction.md b/docs-src/md/introduction.md
similarity index 99%
rename from examples/src/md/introduction.md
rename to docs-src/md/introduction.md
index 00842cb..02d0d02 100644
--- a/examples/src/md/introduction.md
+++ b/docs-src/md/introduction.md
@@ -84,7 +84,7 @@ This is where your content will be injected.
In next section you can find all available options and then more examples.
-See also the `examples` folder. You can run `npm run build-examples` to compile them.
+See also the `docs-src` folder. You can run `npm run build` to compile them.
## Options
@@ -752,7 +752,7 @@ You can add custom rules how attributes are parsed, as behind the scene it's use
## Examples
You can work with ` In next section you can find all available options and then more examples.
See also the
-
examples
+ docs-src
folder. You can run
- npm run build-examples
+ npm run build
to compile them.
@@ -1231,7 +1231,7 @@
<fill>
or you can create component for each "block" of your component, and you can also support both of them.
You can find an example of this inside
- examples/components/modal
+ docs-src/components/modal
. Below is a short explanation about the both approach.
npm i -D posthtml-component
- - This PostHTML plugin provides an HTML-friendly syntax for write components in your templates. -If you are familiar with Blade, you will find similar syntax as this plugin was inspired by it. -See below a basic example, as code is worth a thousand words. -
---- This plugin is still in early stage of development and the current API may change. -
-
Create the component:
-<!-- src/button.html -->
-<button type="button" class="btn">
- <yield></yield>
-</button>
- Use the component:
-<!-- src/index.html -->
-<html>
-<body>
- <x-button type="submit" class="btn-primary">Submit</x-button>
-</body>
-</html>
- Init PostHTML:
-// index.js
-const { readFileSync, writeFileSync } = require('fs')
-
-const posthtml = require('posthtml')
-const components = require('posthtml-components')
-
-posthtml(components({ root: './src' }))
- .process(readFileSync('src/index.html', 'utf8'))
- .then((result) => writeFileSync('dist/index.html', result.html, 'utf8'))
- Result:
-<!-- dist/index.html -->
-<html>
-<body>
- <button type="submit" class="btn btn-primary">Submit</button>
-</body>
-</html>
- - You may ask yourself many questions about this basic examples, and you will find most if not all answers in this readme. In case is missing something, feel free to ask via discussions. -
-But I want to explain a few things now.
-
- First you may notice that our
- src/button.html
- component has a
- type
- and
- class
- attribute, and when we use the component in
- src/index.html
- we add type and class attribute. The result is that
- type
- is override, and
- class
- is merged.
-
- By default
- class
- and
- style
- attributes are merged, while all others attribute are override. You can also override class and style attribute by prepending
- override:
- to the class attribute. Example:
-
<x-button override:class="btn-custom">Submit</x-button>
-
-<!-- Output -->
-<button type="button" class="btn-custom">Submit</button>
-
- All attributes you pass to the component will be added to the first root element of your component, and only if they are not defined as
- props
- via
- <script props>
- . More details on this later.
-
- Second you may notice a
- <yield>
- tag.
-
This is where your content will be injected.
-In next section you can find all available options and then more examples.
-
- See also the
- examples
- folder. You can run
- npm run build-examples
- to compile them.
-
Option | -Default | -Description | -
---|---|---|
- root - | -
- './'
- |
- String value as root path for components lookup. | -
- folders - | -
- ['']
- |
-
- Array of additional multi folders path from
- options.root
- or any defined namespaces root, fallback or custom.
- |
-
- tagPrefix - | -
- x-
- |
- String for tag prefix. The plugin will use RegExp with this string. | -
- tag - | -
- false
- |
-
- String or boolean value for component tag. Use this with
- options.attribute
- . Boolean only false.
- |
-
- attribute - | -
- src
- |
- String value for component attribute for set path. | -
- namespaces - | -
- []
- |
- Array of namespace's root path, fallback path and custom path for override. | -
- namespaceSeparator - | -
- ::
- |
-
- String value for namespace separator to be used with tag name. Example
- <x-namespace::button>
- |
-
- fileExtension - | -
- html
- |
- String value for file extension of the components used for retrieve x-tag file. | -
- yield - | -
- yield
- |
-
- String value for
- <yield>
- tag name. Where main content of component is injected.
- |
-
- slot - | -
- slot
- |
-
- String value for
- <slot>
- tag name. Used with RegExp by appending
- :
- (example
- <slot:slot-name>
- ).
- |
-
- fill - | -
- fill
- |
-
- String value for
- <fill>
- tag name. Used with RegExp by appending
- :
- (example
- <fill:slot-name>
- ).
- |
-
- slotSeparator - | -
- :
- |
-
- String value used for separate
- <slot>
- and
- <fill>
- tag from their names.
- |
-
- push - | -
- push
- |
-
- String value for
- <push>
- tag name.
- |
-
- stack - | -
- stack
- |
-
- String value for
- <stack>
- tag name.
- |
-
- localsAttr - | -
- props
- |
-
- String value used in
- <script props>
- parsed by the plugin to retrieve locals in the components.
- |
-
- expressions - | -
- {}
- |
-
- Object to configure
- posthtml-expressions
- . You can pre-set locals or customize the delimiters for example.
- |
-
- plugins - | -
- []
- |
- PostHTML plugins to apply for every parsed components. | -
- matcher - | -
- [{tag: options.tagPrefix}]
- |
- Array of object used to match the tags. | -
- attrsParserRules - | -
- {}
- |
- Additional rules for attributes parser plugin. | -
- strict - | -
- true
- |
- Boolean value for enable or disable throw an exception. | -
- mergeCustomizer - | -
- function
- |
-
- Function callback passed to lodash
- mergeWith
- for merge
- options.expressions.locals
- and locals passed via attribute
- locals
- .
- |
-
- You can use the components in multiple ways, or also a combination of them.
-Like with
- posthtml-extend
- and
- posthtml-modules
- you can define a tag name in combination with an attribute name for set the path of the components.
-
- For example for the same button component
- src/button.html
- in the basic example we can define the tag name and attribute name and then use it in this way:
-
<!-- src/index.html -->
-<html>
-<body>
- <component src="button.html">Submit</component>
-</body>
-</html>
- Init PostHTML:
-// index.js
-
-require('posthtml')(require('posthtml-components')({ root: './src', tagName: 'component', attribute: 'src' }))
- .process(/* ... */)
- .then(/* ... */)
-
- If you need more control over how to match the tags, you can pass directly an array of matcher or single object via
- options.matcher
- like shown in below example:
-
// index.js
-
-const options = {
- root: './src',
- matcher: [{tag: 'a-tag'}, {tag: 'another-one'}, {tag: new RegExp(`^app-`, 'i')}]
-};
-
-require('posthtml')(require('posthtml-components')(options))
- .process(/* ... */)
- .then(/* ... */)
-
- With
- posthtml-components
- you don't need to specify the path name when you are using
- x-tag-name
- syntax. See below example.
-
Setup PostHTML:
-// index.js
-
-const options = {
- root: './src',
- tagPrefix: 'x-'
-};
-
-require('posthtml')(require('posthtml-components')(options))
- .process(/* ... */)
- .then(/* ... */)
- Use:
-<!-- src/index.html -->
-<html>
-<body>
- <x-button>Submit</x-button>
-</body>
-</html>
-
- If your components are in a subfolder then you can use
- dot
- to access it, example:
-
<!-- Supposing your button component is located in ./src/components/forms/button.html -->
-<x-forms.button>Submit</x-forms.button>
-
- If your components are in a sub-folder with multiple files, then for avoid typing the main file you can use
- index.html
- without specify it.
-Please see below example to understand better.
-
<!-- Supposing your modal component is located in ./src/components/modals/index.html -->
-<x-modal.index>Submit</x-modal.index>
-
-<!-- You can omit "index" part since the file is named "index.html" -->
-<x-modal>Submit</x-modal>
-
- You have full control where to place your components. Once you set the base root path of your components, you can then set multiple folders.
-For example let's suppose your main root is
- ./src
- and then you have several folders where you have your components, for example
- ./src/components
- and
- ./src/layouts
- .
-You can setup the plugin like below:
-
// index.js
-const options = {
- root: './src',
- folders: ['components', 'layouts']
-};
-
-require('posthtml')(require('posthtml-components')(options))
- .process(/* ... */)
- .then(/* ... */)
- - With namespaces you can define a top level root path to your components like shown in below example. -It can be useful for handle custom theme, where you define a specific top level root, with fallback root when component it's not found, -and a custom root for override, something like a child theme. -
-Thanks to namespace, you can create folders structure like below:
-src
- (base root folder)
- components
- (folder for components like modal, button, etc.)
- layouts
- (folder for layout components like base layout, header, footer, etc.)
- theme-dark
- (namespace folder for theme-dark)
- components
- (folder for components for theme dark)
- layouts
- (folder for layout components for dark theme)
- theme-light
- (namespace folder for theme-light)
- components
- (folder for components for light theme)
- layouts
- (folder for layout components for dark theme)
- custom
- (custom folder for override your namespace themes)
- theme-dark
- (custom folder for override dark theme)
- components
- (folder for override components of theme dark)
- layouts
- (folder for override layout components of dark theme)
- theme-light
- (custom folder for override light theme)
- components
- (folder for override components of theme dark)
- layouts
- (folder for override layout components of dark theme)
- And the options would be like:
-// index.js
-const options = {
- // Main root for component without namespace
- root: './src',
- // Folders is always appended in 'root' or any defined namespace's folders (base, fallback or custom)
- folders: ['components', 'layouts'],
- namespaces: [{
- // Namespace name will be prepend to tag name (example <x-theme-dark::button>)
- name: 'theme-dark',
- // Base root of the namespace
- root: './src/theme-dark',
- // Fallback root when a component it's not found in namespace
- fallback: './src',
- // Custom root for override, the lookup happen first here
- custom: './src/custom/theme-dark'
- }, {
- // Light theme
- name: 'theme-light',
- root: './src/theme-light',
- fallback: './src',
- custom: './src/custom/theme-light'
- }, {
- /* ... */
- }]
-};
- Use the component namespace:
-<!-- src/index.html -->
-<html>
-<body>
- <x-theme-dark::button>Submit</theme-dark::button>
- <x-theme-light::button>Submit</theme-light::button>
-</body>
-</html>
- - Of course, you can change this folder structure as you prefer according to your project requirements. -
-- Your components can inject code in specific slots you define, and then you can fill this content when you use the component. -Find below a simple example. -
-Create the component:
-<!-- src/modal.html -->
-<div class="modal">
- <div class="modal-header">
- <slot:header></slot:header>
- </div>
- <div class="modal-body">
- <slot:body></slot:body>
- </div>
- <div class="modal-footer">
- <slot:footer></slot:footer>
- </div>
-</div>
- Use the component:
-<!-- src/index.html -->
-<x-modal>
- <fill:header>Header content</fill:header>
- <fill:body>Body content</fill:body>
- <fill:footer>Footer content</fill:footer>
-</x-modal>
- Result:
-<!-- dist/index.html -->
-<div class="modal">
- <div class="modal-header">
- Header content
- </div>
- <div class="modal-body">
- Body content
- </div>
- <div class="modal-footer">
- Footer content
- </div>
-</div>
- - By default the content is replaced, but you can also prepend or append the content, or keep the default content by not filling the slot. -
-Add some default content in the component:
-<!-- src/modal.html -->
-<div class="modal">
- <div class="modal-header">
- <slot:header>Default header</slot:header>
- </div>
- <div class="modal-body">
- <slot:body>content</slot:body>
- </div>
- <div class="modal-footer">
- <slot:footer>Footer</slot:footer>
- </div>
-</div>
- <!-- src/index.html -->
-<x-modal>
- <fill:body prepend>Prepend body</fill:body>
- <fill:footer append>content</fill:footer>
-</x-modal>
- Result:
-<!-- dist/index.html -->
-<div class="modal">
- <div class="modal-header">
- Default header
- </div>
- <div class="modal-body">
- Prepend body content
- </div>
- <div class="modal-footer">
- Footer content
- </div>
-</div>
- - You can push content to named stacks which can be rendered somewhere else in another place. This can be particularly useful for specifying any JavaScript or CSS required by your components. -
-
- First of all define a
- <stack>
- anywhere in your code, for example:
-
<!-- src/index.html -->
-<html>
-<head>
-<stack name="styles"></stack>
-</head>
-<body>
-
-<x-modal>
- <fill:header>Header content</fill:header>
- <fill:body>Body content</fill:body>
- <fill:footer>Footer content</fill:footer>
-</x-modal>
-
-<stack name="scripts"></stack>
-</body>
-</html>
- - Then in modal components, or any other child components, you can push content to this stack. -
-<!-- src/modal.html -->
-<div class="modal">
- <div class="modal-header">
- <slot:header></slot:header>
- </div>
- <div class="modal-body">
- <slot:body></slot:body>
- </div>
- <div class="modal-footer">
- <slot:footer></slot:footer>
- </div>
-</div>
-
-<push name="styles">
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
-</push>
-
-<push name="scripts">
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
-</push>
- The output will be:
-<!-- dist/index.html -->
-<html>
-<head>
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
-</head>
-<body>
-<div class="modal">
- <div class="modal-header">
- Header content
- </div>
- <div class="modal-body">
- Body content
- </div>
- <div class="modal-footer">
- Footer content
- </div>
-</div>
-<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
-</body>
-</html>
-
- The
- once
- attribute allows you to push content only once per rendering cycle. For example, if you are rendering a given component within a loop, you may wish to only push the JavaScript and CSS the first time the component is rendered.
-
Example.
-<!-- src/modal.html -->
-<div class="modal">
- <!-- ... -->
-</div>
-
-<!-- The push content will be pushed only once in the stack -->
-
-<push name="styles" once>
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
-</push>
-
-<push name="scripts" once>
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
-</push>
-
- By default the content is pushed in the stack in the given order.
-If you would like to prepend content onto the beginning of a stack, you should use the
- prepend
- attribute:
-
<push name="scripts">
- <!-- This will be second -->
- <script src="/example.js"></script>
-</push>
-
-<!-- Later... -->
-
-<push name="scripts" prepend>
- <!-- This will be first -->
- <script src="/example-2.js"></script>
-</push>
-
- Behind the
- props
- there is powerful
- posthtml-expressions
- plugin, with feature to pass
- props
- (locals) via attributes and manipulate them via
- <script props>
- .
-
Let's see how it works with a few examples starting with a basic one.
-Create the component:
-<!-- src/my-component.html -->
-<script props>
- module.exports = {
- prop: locals.prop || 'Default prop value'
- }
-</script>
-<div>
- {{ prop }}
-</div>
- Use:
-<x-my-component prop="Hello world!"></x-my-component>
- The output will be:
-<div>
- Hello world!
-</div>
-
- Without passing
- prop
- via attribute then the output would be
- Default prop value
- , as shown below.
-
Use component without passing prop:
-<x-my-component></x-my-component>
- The output will be:
-<div>
- Default prop value
-</div>
-
- If you don't add the props in
- <script props>
- inside your component, all props will be added as attributes to the first node of your component or to the node with attribute
- attributes
- .
-More details on this in the next section.
-
- So in the
- <script props>
- you have access to passed props via object
- locals
- , and you can add any logic you need inside of it.
-
Create the component:
-<!-- src/modal.html -->
-<script props>
- module.exports = {
- title: locals.title || 'Default title',
- size: locals.size ? `modal-${locals.size}` : '',
- items: Array.isArray(locals.items) ? locals.items.concat(['first', 'second']) : ['first', 'second']
- }
-</script>
-<div class="modal {{ size }}">
- <div class="modal-header">
- {{ title }}
- </div>
- <div class="modal-body">
- <each loop="item in items"><span>{{ item }}</span></each>
- </div>
-</div>
- Use:
-<x-modal size="xl" title="My modal title" items='["third", "fourth"]' class="modal-custom"></x-modal>
- The output will be:
-<div class="modal modal-custom modal-xl">
- <div class="modal-header">
- My modal title
- </div>
- <div class="modal-body">
- <span>first</span>
- <span>second</span>
- <span>third</span>
- <span>fourth</span>
- </div>
-</div>
-
- You can also notice how the
- class
- attribute is merged with
- class
- attribute of the first node. Let's see in next section more about this.
-
- You can change how attributes are merged with global locals defined via options by passing a callback function used by lodash method - mergeWith - . -
-- By default, all props are scoped to the component, and are not available to nested components. You can however change this accordingly to your need. -Let's see below example. -
-Create a component:
-<!-- src/child.html -->
-<script props>
- module.exports = {
- prop: locals.prop || 'Default prop value'
- }
-</script>
-<div>
- Prop in child: {{ prop }}
-</div>
- Create another component that use the first one:
-<!-- src/parent.html -->
-<script props>
- module.exports = {
- prop: locals.prop || 'Default prop value'
- }
-</script>
-<div>
- Prop in parent: {{ prop }}
- <x-child></x-child>
-</div>
- Use:
-<x-parent prop="My prop"></x-parent>
- The output will be:
-<div>
- Prop in parent: My prop
- <div>
- Prop in child: Default prop value
- </div>
-</div>
-
- As you can see
- prop
- in
- x-child
- component are default value and not the one set via
- x-parent
- . Prepend
- aware:
- to the attribute name to pass the props to nested components.
-
<x-parent aware:prop="My prop"></x-parent>
- The output now will be:
-<div>
- Prop in parent: My prop
- <div>
- Prop in child: My prop
- </div>
-</div>
-
- Your can pass any attributes to your components and this will be added to the first node of your component, or to the node with an attribute named
- attributes
- .
-By default
- class
- and
- style
- are merged with existing
- class
- and
- style
- attribute.
-All others attributes are override by default.
-Only attribute not defined as
- props
- will be used.
-
As already seen in basic example:
-<!-- src/button.html -->
-<script props>
- module.exports = {
- label: locals.label || 'A button'
- }
-</script>
-<button type="button" class="btn">
- {{ label }}
-</button>
- Use the component:
-<!-- src/index.html -->
-<x-button type="submit" class="btn-primary" label="My button"></x-button>
- Result:
-<!-- dist/index.html -->
-<button type="submit" class="btn btn-primary">My button</button>
-
- As you may notice the
- label
- attribute is not added as attribute, since it's defined as a
- props
- .
-
If you are familiar with Laravel Blade, this is also how Blade handle this.
-
- As said early,
- class
- and
- style
- are merged by default, if you want to override them, just prepend
- override:
- to the attribute name:
-
<!-- src/index.html -->
-<x-button type="submit" override:class="btn-custom" label="My button"></x-button>
- Result:
-<!-- dist/index.html -->
-<button type="submit" class="btn-custom">My button</button>
-
- If you want to use another node for add such attributes, then you can add the attribute
- attributes
- like shown below.
-
<!-- src/my-component.html -->
-<div class="first-node">
- <div class="second-node" attributes>
- Hello world!
- </div>
-</div>
- Use the component:
-<!-- src/index.html -->
-<x-my-component class="my-class"></x-my-component>
- Result:
-<!-- dist/index.html -->
-<div class="first-node">
- <div class="second-node my-class">
- Hello world!
- </div>
-</div>
- - You can add custom rules how attributes are parsed, as behind the scene it's used - posthtml-attrs-parser - plugin. -
-
- You can work with
- <slot>
- and
- <fill>
- or you can create component for each "block" of your component, and you can also support both of them.
-You can find an example of this inside
- examples/components/modal
- . Below is a short explanation about the both approach.
-
- Let's suppose we want to create a component for - bootstrap modal - . The code required is: -
-<!-- Modal HTML -->
-<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">
- <h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1>
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
- </div>
- <div class="modal-body">
- ...
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
- <button type="button" class="btn btn-primary">Save changes</button>
- </div>
- </div>
- </div>
-</div>
- - There is almost three block of code: the header, the body and the footer. -So we could create our component with three slot like below: -
-<!-- Modal component -->
-<div class="modal fade" tabindex="-1" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content">
- <div class="modal-header">
- <slot:header></slot:header>
- <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
- </div>
- <div class="modal-body">
- <slot:body></slot:body>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
- <slot:footer></slot:footer>
- </div>
- </div>
- </div>
-</div>
- In this case we can use it like:
-<x-modal
- id="exampleModal"
- aria-labelledby="exampleModalLabel"
->
- <slot:header>
- <h5 class="modal-title" id="exampleModalLabel">My modal</h5>
- </slot:header>
-
- <slot:body>
- Modal body content goes here...
- </slot:body>
-
- <slot:footer close="false">
- <button type="button" class="btn btn-primary">Confirm</button>
- </slot:footer>
-</x-modal>
- - Another way is to split the component in small component, my preferred way, because you can pass attributes to each of them. -So we create the component with a main component and then three different small component: -
-<!-- Main modal component -->
-<div class="modal fade" tabindex="-1" aria-hidden="true">
- <div class="modal-dialog">
- <div class="modal-content">
- <yield></yield>
- </div>
- </div>
-</div>
- <!-- Header modal component -->
-<div class="modal-header">
- <yield></yield>
-</div>
- <!-- Body modal component -->
-<div class="modal-body">
- <yield></yield>
-</div>
- <!-- Footer modal component -->
-<div class="modal-footer">
- <yield></yield>
-</div>
- And then you can use it like below example:
-<x-modal
- id="exampleModal"
- aria-labelledby="exampleModalLabel"
->
- <x-modal.header>
- <h5 class="modal-title" id="exampleModalLabel">My modal</h5>
- </x-modal.header>
-
- <x-modal.body>
- Modal body content goes here...
- </x-modal.body>
-
- <x-modal.footer>
- <button type="button" class="btn btn-primary">Confirm</button>
- </x-modal.footer>
-</x-modal>
- - As said in this way you can pass attributes to each of them, without defining props. -
-- You can also combine both way, and then use them with slots or with small component: -
-<!-- Modal -->
-<div
- class="modal fade"
- tabindex="-1"
- aria-hidden="true"
- aria-modal="true"
- role="dialog"
->
- <div class="modal-dialog">
- <div class="modal-content">
- <if condition="$slots.header?.filled">
- <x-modal.header>
- <slot:header></slot:header>
- </x-modal.header>
- </if>
- <if condition="$slots.body?.filled">
- <x-modal.body>
- <slot:body></slot:body>
- </x-modal.body>
- </if>
- <if condition="$slots.footer?.filled">
- <x-modal.footer close="{{ $slots.footer?.locals.close }}">
- <slot:footer></slot:footer>
- </x-modal.footer>
- </if>
- <yield></yield>
- </div>
- </div><!-- /.modal-dialog -->
-</div><!-- /.modal -->
-
- Now you can use your component with slots or with small components.
-As you may notice, by using slots, you already can use also your small components, and so you can also pass props
-via
- $slots
- which has all the
- props
- passed via slot, and as well check if slot is filled.
-
- If you are migrating from
- posthtml-extend
- and/or
- posthtml-modules
- please to follow updates here:
- posthtml-components/issues/16
- .
-
- Quickly design with PostHTML, the simple, yet powerful tool for transforming HTML/XML with JS plugins. - Fueled with - x-components - plugin which give you additional superpowers! -
-- Currently - v1.0.0-beta.10 - ยท - Changelog -
-- first - : First default item -
-- second - : Second default item -
-- first - : First overriden item -
-- second - : Second overriden item -
-- first - : First merged item -
-- second - : Second merged item -
-- anObjectMerged1 - : {"first":"First1 merged item","second":"Second1 merged item","anObjectMerged2":{"first":"First2 merged item","second":"Second2 merged item"}} -
-My default string
-My default override string
-- 1 - : My comment 1 -
-- 2 - : My comment 2 -
-- 0 - : {"id":1,"title":"My default title 1"} -
-- 1 - : {"id":2,"title":"My default title 2"} -
-- 0 - : first -
-- 1 - : second -
-No
- My filled slot - Hello -