Skip to content
Merged
167 changes: 160 additions & 7 deletions znai-docs/znai/llm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ answer-link: znai-from-export/introduction/getting-started#command-line
## CLI download

Download and unzip
[znai](https://repo.maven.apache.org/maven2/org/testingisdocumenting/znai/znai-dist/1.90.1/znai-dist-1.90.1-znai.zip).
Add it to your `PATH`.
[znai](https://repo.maven.apache.org/maven2/org/testingisdocumenting/znai/znai-dist/1.91/znai-dist-1.91-znai.zip). Add
it to your `PATH`.

## Brew

Expand All @@ -162,7 +162,7 @@ answer-link: znai-from-export/introduction/getting-started#maven-plugin
<plugin>
<groupId>org.testingisdocumenting.znai</groupId>
<artifactId>znai-maven-plugin</artifactId>
<version>1.90.1</version>
<version>1.91</version>
</plugin>
```

Expand Down Expand Up @@ -4399,6 +4399,66 @@ answer-link: znai-from-export/visuals/attention-signs#attention-block-types
attention-<type>
```

# Visuals :: Attention Signs :: Custom Attention Block
answer-link: znai-from-export/visuals/attention-signs#custom-attention-block

Use `attention-custom` when the built-in types are not enough. The free form parameter defines the type. It is used as a
CSS class name, exactly like `note`, `warning`, and the other built-in types.

```markdown
```attention-custom my-type
hello world
```
```


`attention-custom` only provides the markup placeholders. Each guide is responsible for implementing the CSS for its own
types.

Use in combination with `style.css`. Scope rules under `.theme-znai-dark` to define dark mode colors.

```css
.znai-attention-block.my-type {
border-left: 3px solid #6f42c1;
background: #f3effb;
}

.znai-attention-block.my-type .znai-attention-block-icon {
color: #6f42c1;
}

.theme-znai-dark .znai-attention-block.my-type {
border-left-color: #b794f6;
background: rgba(159, 122, 234, 0.12);
}

.theme-znai-dark .znai-attention-block.my-type .znai-attention-block-icon {
color: #b794f6;
}
```

# Visuals :: Attention Signs :: Custom Icon
answer-link: znai-from-export/visuals/attention-signs#custom-icon

Unlike the built-in types, a custom type has no icon by default. Use the `icon` parameter to display one.

To pick an icons to use go to [Feather icons](https://feathericons.com/).

```markdown
```attention-custom my-type {icon: "zap"}
hello world
```
```


Combine `icon` with the optional `label`

```markdown
```attention-custom my-type {icon: "zap", label: "Consider"}
hello world
```
```

# Visuals :: Images :: Standard Markdown
answer-link: znai-from-export/visuals/images#standard-markdown

Expand Down Expand Up @@ -4744,7 +4804,7 @@ scenario("capture screenshot") {
"type" : "badge",
"text" : "2",
"x" : 367,
"y" : 486,
"y" : 285,
"align" : "Center"
} ],
"pixelRatio" : 2
Expand Down Expand Up @@ -5114,6 +5174,15 @@ In presentation mode, rendered expressions will automatically scale to make use

Note: Rendering is done by using [Mermaid](https://mermaid-js.github.io/mermaid/#/) library.

# Visuals :: Mermaid Diagrams :: Large Diagrams
answer-link: znai-from-export/visuals/mermaid-diagrams#large-diagrams

A diagram that is too large to fit the page width is shrunk to fit and can become hard to read. Click the diagram to
open it in a full screen overlay where you can:

- scroll/`wheel` to zoom towards the cursor
- drag to pan

# Visuals :: Mermaid Diagrams :: External File
answer-link: znai-from-export/visuals/mermaid-diagrams#external-file

Expand Down Expand Up @@ -8950,7 +9019,7 @@ scenario("capture screenshot") {
"type" : "badge",
"text" : "2",
"x" : 367,
"y" : 486,
"y" : 285,
"align" : "Center"
} ],
"pixelRatio" : 2
Expand Down Expand Up @@ -9239,8 +9308,8 @@ answer-link: znai-from-export/plugins/javascript-plugin#function-signature
Your function receives three arguments:

* `node` — the parent `div` to append content to.
* `args` — the parameters passed from markdown. Framework-level keys (`title`, `wide`, `className`, `anchorId`) are
handled by znai and not forwarded.
* `args` — the parameters passed from markdown. Framework-level keys (`title`, `wide`, `className`, `anchorId`, `height`)
are handled by znai and not forwarded.
* `themeObservable` — live access to the current znai theme.

```javascript
Expand Down Expand Up @@ -9305,6 +9374,39 @@ Pass `wide: true` to span the full page width, matching wide images and iframes.
}
```

# Plugins :: Javascript Plugin :: Height
answer-link: znai-from-export/plugins/javascript-plugin#height

By default the block grows to fit whatever the function renders into it. Pass `height` to pin the block to a fixed size
— content past it scrolls inside the viewport znai gives the function.

`height` accepts either a number (treated as pixels) or any CSS length string like `"320px"` or `"30vh"`.

The `activityFeed` function below appends one row per event. Without `height`, all twelve rows render and the block
grows to fit them:

```markdown
:include-javascript-function: activityFeed {
title: "deploys",
events: [
{time: "09:14", action: "build started", detail: "commit a31f9b on main"},
{time: "09:17", action: "tests passed", detail: "248 / 248 green"},
...
]
}
```


Add `height` and the same twelve events scroll inside a fixed-size box instead:

```markdown
:include-javascript-function: activityFeed {
title: "deploys",
height: 220,
events: [/* same twelve events */]
}
```

# Plugins :: Javascript Plugin :: Styling With A Class Name
answer-link: znai-from-export/plugins/javascript-plugin#styling-with-a-class-name

Expand Down Expand Up @@ -9469,6 +9571,52 @@ The function below powers the examples on this page. It reads the initial theme
})();
```

```js
/*
* sample plugin showing a list of rows that grows to fit its content.
*
* the parent node sized by znai (`height` arg) is what constrains us — when
* unset, the feed renders all rows tall enough to show them all; when set,
* the same content scrolls inside the fixed viewport znai gave us.
*/
(function () {
function createElement(tagName, className, textContent) {
var el = document.createElement(tagName);
el.className = className;
if (textContent !== undefined) {
el.textContent = textContent;
}
return el;
}

function buildRow(event) {
var row = createElement("div", "activity-feed-row");
row.appendChild(createElement("span", "activity-feed-time", event.time || ""));
row.appendChild(createElement("span", "activity-feed-action", event.action || ""));
row.appendChild(createElement("span", "activity-feed-detail", event.detail || ""));
return row;
}

window.activityFeed = function (node, args, themeObservable) {
var events = Array.isArray(args.events) ? args.events : [];

var feed = createElement("div", "activity-feed");
events.forEach(function (event) {
feed.appendChild(buildRow(event));
});

node.appendChild(feed);

function applyTheme(themeName) {
feed.classList.toggle("activity-feed-dark", themeName === "dark");
}

applyTheme(themeObservable.current);
themeObservable.subscribe(applyTheme);
};
})();
```

# Plugins :: User Defined Plugins :: Overview
answer-link: znai-from-export/plugins/user-defined-plugins#overview

Expand Down Expand Up @@ -9941,6 +10089,11 @@ export PATH=$(pwd)/dist:$PATH
znai --version
```

# Release Notes :: 2026 :: 1.91
answer-link: znai-from-export/release-notes/2026#191



# Release Notes :: 2026 :: 1.90.1
answer-link: znai-from-export/release-notes/2026#1901

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* Add: Search on the page with [Read More](visuals/read-more) blocks auto opens the blocks
* Add: Optimize guide level search rendering and debounce
* Add: Guide level search keeps `_` symbol as it is often part of the search term
4 changes: 4 additions & 0 deletions znai-docs/znai/release-notes/2026.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.92

:include-markdowns: 1.92

# 1.91

:include-markdowns: 1.91
Expand Down
28 changes: 9 additions & 19 deletions znai-reactjs/src/doc-elements/bullets/bulletUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

import { walkContentNodes } from '../default-elements/contentTreeWalker'

export function startsWithIcon(content) {
return content &&
content.length && content[0].type === 'Paragraph' &&
Expand Down Expand Up @@ -64,29 +66,17 @@ export function extractTextLinesEmphasisOrFull(content) {

function extractText(listItem, emphasisedOnly) {
const result = []
collectTextRecursively(result, listItem.content, emphasisedOnly, false)

return capitalizeFirstLetter(result.join(" "))
}

function collectTextRecursively(result, content, emphasisedOnly, withinEmphasis) {
if (! content) {
return
}
walkContentNodes(listItem.content, (item, ancestors) => {
if (item.type !== "SimpleText") {
return
}

content.forEach(item => {
if (item.type === "SimpleText") {
if (emphasisedOnly && withinEmphasis) {
result.push(item.text)
} else if (! emphasisedOnly) {
result.push(item.text)
}
} else {
collectTextRecursively(result, item.content, emphasisedOnly, withinEmphasis || isEmphasis(item))
if (! emphasisedOnly || ancestors.some(isEmphasis)) {
result.push(item.text)
}
})

return result
return capitalizeFirstLetter(result.join(" "))
}

function isEmphasis(docElement) {
Expand Down
8 changes: 5 additions & 3 deletions znai-reactjs/src/doc-elements/default-elements/DocElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export type ElementsLibraryMap = { [key: string]: any };
export type DocElementContent = DocElementPayload[];

interface CommonProps {
isPartOfSearch?: boolean; // when element is rendered in search preview or after section is selected as search result
// matched search terms, present only when element is rendered in search preview or after section
// is selected as search result; lets elements with hidden content decide what to reveal during search
searchSnippets?: string[];
noGap?: boolean;
content?: DocElementContent;
next?: DocElementPayload;
Expand All @@ -41,7 +43,7 @@ export interface WithElementsLibrary {
/**
* uses a given set of components to render DocElements like links, paragraphs, code blocks, etc
*/
export function DocElement({ content, elementsLibrary, isPartOfSearch }: DocElementProps) {
export function DocElement({ content, elementsLibrary, searchSnippets }: DocElementProps) {
if (!content) {
return null;
}
Expand All @@ -52,7 +54,7 @@ export function DocElement({ content, elementsLibrary, isPartOfSearch }: DocElem
while (contentProvider.peekCurrent()) {
const found = findRenderComponent(elementsLibrary, contentProvider);
const ElementToUse = found.component;
const propsToUse = { isPartOfSearch, ...found.propsToUse };
const propsToUse = { searchSnippets, ...found.propsToUse };

if (!ElementToUse) {
console.warn("can't find component to display: " + JSON.stringify(contentProvider.peekCurrent()));
Expand Down
Loading
Loading