slexkit 0.3.1 → 0.3.2
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/ai/llms-full.txt +14 -2
- package/dist/ai/llms.txt +1 -1
- package/dist/ai/slexkit-ai-manifest.json +11 -11
- package/dist/base.css +0 -46
- package/dist/runtime.cjs +46 -24
- package/dist/runtime.js +46 -24
- package/dist/slexkit.cjs +46 -24
- package/dist/slexkit.css +0 -46
- package/dist/slexkit.js +46 -24
- package/dist/types/engine/types.d.ts +1 -1
- package/dist/types/version.d.ts +2 -2
- package/dist/umd/slexkit.tooling.umd.js +45 -23
- package/dist/umd/slexkit.umd.js +46 -24
- package/package.json +1 -1
- package/src/styles/layout.css +0 -46
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to SlexKit.
|
|
4
4
|
|
|
5
|
+
## v0.3.2 - Host CSS isolation and repeated layout hardening
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- `$for` rendering now uses comment anchors and direct child insertion instead of a wrapper element that depended on `display: contents`.
|
|
9
|
+
- Site-only mobile navigation CSS moved out of the runtime base stylesheet and into the documentation site shell.
|
|
10
|
+
- Component accessors now share one reactive effect across subscribers instead of creating duplicate subscriber fan-out work.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Obsidian and other Markdown hosts no longer need to rewrite `$for` wrapper CSS to avoid `display: contents`, preserving grid and row layouts for repeated items.
|
|
14
|
+
- Published runtime base CSS no longer leaks `#mobileNav` or `body[data-mobile-nav-open]` selectors into host pages.
|
|
15
|
+
- Custom renderers that return no element no longer leave invalid `$for` slots behind during diffing or cleanup.
|
|
16
|
+
|
|
5
17
|
## v0.3.1 - Host stability and control rendering hardening
|
|
6
18
|
|
|
7
19
|
### Added
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<a href="README.zh-CN.md">简体中文</a>
|
|
16
16
|
</p>
|
|
17
17
|
<p>
|
|
18
|
-
<img alt="version" src="https://img.shields.io/badge/version-0.3.
|
|
18
|
+
<img alt="version" src="https://img.shields.io/badge/version-0.3.2-18181b">
|
|
19
19
|
<img alt="script" src="https://img.shields.io/badge/Slex-v0.1-18181b">
|
|
20
20
|
<img alt="TypeScript" src="https://img.shields.io/badge/runtime-TypeScript-3178c6">
|
|
21
21
|
<img alt="Svelte 5" src="https://img.shields.io/badge/components-Svelte_5-ff3e00">
|
package/README.zh-CN.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<a href="README.md">English</a>
|
|
16
16
|
</p>
|
|
17
17
|
<p>
|
|
18
|
-
<img alt="version" src="https://img.shields.io/badge/version-0.3.
|
|
18
|
+
<img alt="version" src="https://img.shields.io/badge/version-0.3.2-18181b">
|
|
19
19
|
<img alt="script" src="https://img.shields.io/badge/Slex-v0.1-18181b">
|
|
20
20
|
<img alt="TypeScript" src="https://img.shields.io/badge/runtime-TypeScript-3178c6">
|
|
21
21
|
<img alt="Svelte 5" src="https://img.shields.io/badge/components-Svelte_5-ff3e00">
|
package/dist/ai/llms-full.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SlexKit Full LLM Documentation
|
|
2
2
|
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
|
|
5
5
|
This file concatenates SlexKit's canonical English Markdown docs. `slex` fences are preserved exactly.
|
|
6
6
|
|
|
@@ -27,7 +27,7 @@ Source: README.md
|
|
|
27
27
|
<a href="README.zh-CN.md">简体中文</a>
|
|
28
28
|
</p>
|
|
29
29
|
<p>
|
|
30
|
-
<img alt="version" src="https://img.shields.io/badge/version-0.3.
|
|
30
|
+
<img alt="version" src="https://img.shields.io/badge/version-0.3.2-18181b">
|
|
31
31
|
<img alt="script" src="https://img.shields.io/badge/Slex-v0.1-18181b">
|
|
32
32
|
<img alt="TypeScript" src="https://img.shields.io/badge/runtime-TypeScript-3178c6">
|
|
33
33
|
<img alt="Svelte 5" src="https://img.shields.io/badge/components-Svelte_5-ff3e00">
|
|
@@ -7574,6 +7574,18 @@ slexkitRenderMode: component
|
|
|
7574
7574
|
|
|
7575
7575
|
All notable changes to SlexKit.
|
|
7576
7576
|
|
|
7577
|
+
## v0.3.2 - Host CSS isolation and repeated layout hardening
|
|
7578
|
+
|
|
7579
|
+
### Changed
|
|
7580
|
+
- `$for` rendering now uses comment anchors and direct child insertion instead of a wrapper element that depended on `display: contents`.
|
|
7581
|
+
- Site-only mobile navigation CSS moved out of the runtime base stylesheet and into the documentation site shell.
|
|
7582
|
+
- Component accessors now share one reactive effect across subscribers instead of creating duplicate subscriber fan-out work.
|
|
7583
|
+
|
|
7584
|
+
### Fixed
|
|
7585
|
+
- Obsidian and other Markdown hosts no longer need to rewrite `$for` wrapper CSS to avoid `display: contents`, preserving grid and row layouts for repeated items.
|
|
7586
|
+
- Published runtime base CSS no longer leaks `#mobileNav` or `body[data-mobile-nav-open]` selectors into host pages.
|
|
7587
|
+
- Custom renderers that return no element no longer leave invalid `$for` slots behind during diffing or cleanup.
|
|
7588
|
+
|
|
7577
7589
|
## v0.3.1 - Host stability and control rendering hardening
|
|
7578
7590
|
|
|
7579
7591
|
### Added
|
package/dist/ai/llms.txt
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slexkit-ai-docs",
|
|
3
3
|
"packageName": "slexkit",
|
|
4
|
-
"version": "0.3.
|
|
5
|
-
"generatedAt": "2026-06-
|
|
4
|
+
"version": "0.3.2",
|
|
5
|
+
"generatedAt": "2026-06-20T09:40:31.853Z",
|
|
6
6
|
"docs": {
|
|
7
7
|
"llms.txt": {
|
|
8
8
|
"path": "/llms.txt",
|
|
9
9
|
"title": "llms.txt",
|
|
10
10
|
"summary": "- [Full documentation](/llms-full.txt): all canonical English docs pages in one text file.",
|
|
11
|
-
"hash": "
|
|
11
|
+
"hash": "b492e34b"
|
|
12
12
|
},
|
|
13
13
|
"llms-full.txt": {
|
|
14
14
|
"path": "/llms-full.txt",
|
|
15
15
|
"title": "llms-full.txt",
|
|
16
|
-
"summary": "Version: 0.3.
|
|
17
|
-
"hash": "
|
|
16
|
+
"summary": "Version: 0.3.2",
|
|
17
|
+
"hash": "34989439"
|
|
18
18
|
},
|
|
19
19
|
"llms-components.txt": {
|
|
20
20
|
"path": "/llms-components.txt",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"href": "/",
|
|
57
57
|
"rawHref": "/README.md",
|
|
58
58
|
"sourcePath": "README.md",
|
|
59
|
-
"body": "<div align=\"center\">\n <p>\n <img src=\"site/assets/logo.svg\" alt=\"SlexKit\" width=\"84\" height=\"84\" />\n </p>\n <h1>SlexKit</h1>\n <p><strong>Streaming Live EXpressions Kit</strong></p>\n <p>\n \"Docs as tools, tools as docs.\" Give Markdown interactive power and make every AI output come alive.\n </p>\n <p>\n <a href=\"site/content/guides/intro/en-US.md\">Documentation</a> ·\n <a href=\"site/content/components/accordion/en-US.md\">Components</a> ·\n <a href=\"site/content/reference/spec/en-US.md\">Specification</a> ·\n <a href=\"site/content/guides/ai-agents/en-US.md\">AI / Agents</a> ·\n <a href=\"README.zh-CN.md\">简体中文</a>\n </p>\n <p>\n <img alt=\"version\" src=\"https://img.shields.io/badge/version-0.3.
|
|
60
|
-
"hash": "
|
|
59
|
+
"body": "<div align=\"center\">\n <p>\n <img src=\"site/assets/logo.svg\" alt=\"SlexKit\" width=\"84\" height=\"84\" />\n </p>\n <h1>SlexKit</h1>\n <p><strong>Streaming Live EXpressions Kit</strong></p>\n <p>\n \"Docs as tools, tools as docs.\" Give Markdown interactive power and make every AI output come alive.\n </p>\n <p>\n <a href=\"site/content/guides/intro/en-US.md\">Documentation</a> ·\n <a href=\"site/content/components/accordion/en-US.md\">Components</a> ·\n <a href=\"site/content/reference/spec/en-US.md\">Specification</a> ·\n <a href=\"site/content/guides/ai-agents/en-US.md\">AI / Agents</a> ·\n <a href=\"README.zh-CN.md\">简体中文</a>\n </p>\n <p>\n <img alt=\"version\" src=\"https://img.shields.io/badge/version-0.3.2-18181b\">\n <img alt=\"script\" src=\"https://img.shields.io/badge/Slex-v0.1-18181b\">\n <img alt=\"TypeScript\" src=\"https://img.shields.io/badge/runtime-TypeScript-3178c6\">\n <img alt=\"Svelte 5\" src=\"https://img.shields.io/badge/components-Svelte_5-ff3e00\">\n <img alt=\"license\" src=\"https://img.shields.io/badge/license-MIT-16a34a\">\n </p>\n</div>\n\n## Live interface blocks inside Markdown\n\n**SlexKit** turns explicit `slex` Markdown fences into live, stateful UI blocks. A Slex source is just a JavaScript object literal: `g` holds state and logic, `layout` describes the component tree, and the browser runtime renders the result in place.\n\nIt is built for chat messages, documents, agent panels, tool results, and AI-authored dashboards. It is not a full application framework.\n\n## Installation\n\n> Just want to use SlexKit in Obsidian? Open **Settings -> Community plugins**, search for **SlexKit**, then install and enable it. The npm package below is for developers integrating SlexKit into web apps, Markdown renderers, Streamdown, or custom hosts.\n\n```sh\nnpm install slexkit\n```\n\n```ts\nimport { mount } from \"slexkit\";\nimport \"slexkit/style.css\";\n```\n\n## Usage\n\n```html\n<div id=\"app\"></div>\n\n<script type=\"module\">\n import { mount } from \"slexkit\";\n import \"slexkit/style.css\";\n\n mount(\n {\n slex: \"0.1\",\n namespace: \"hello\",\n g: { name: \"World\", count: 0 },\n layout: {\n \"card:greeting\": {\n title: \"Greeting\",\n \"text:message\": {\n \"$text\": \"'Hello, ' + g.name + '! Count: ' + g.count\"\n },\n \"button:add\": {\n label: \"+1\",\n onclick: \"g.count++\"\n }\n }\n }\n },\n document.getElementById(\"app\")\n );\n</script>\n```\n\n## Markdown Native\n\nSlexKit-capable hosts process explicit `slex` fences only. Plain `js`, `json`, and unlabeled code blocks stay inert.\n\n````md\n```slex\n{\n slex: \"0.1\",\n namespace: \"status\",\n g: { done: 3, total: 4 },\n layout: {\n \"badge:state\": { label: \"Ready\", tone: \"success\" },\n \"text:summary\": { \"$text\": \"g.done + '/' + g.total + ' complete'\" }\n }\n}\n```\n\n**Status:** Ready. 3/4 complete.\n````\n\nMarkdown platforms without SlexKit support show the fallback text. Hosts with SlexKit render the interactive UI.\n\n## What You Get\n\n- **Zero-build Slex source**: object literals with no imports, scaffolding, or component bundling in the generated output.\n- **Reactive `g` / `layout` model**: centralized state and logic with declarative component trees.\n- **Expression pipes**: `$` read expressions for dynamic props and `on*` write expressions for events.\n- **Directives**: `$if` and `$for` for conditional rendering and keyed list reconciliation.\n- **Official Svelte components**: 40+ layout, input, content, display, disclosure, feedback, and tooling components.\n- **Extensible registry**: custom component types, Svelte renderers, and component state modes.\n- **Trusted and secure runtimes**: host-realm rendering for trusted content, sandbox iframe rendering for untrusted source.\n- **ToolHost**: confirm, choose, and fill-form templates for structured AI tool-call UX.\n- **AI-friendly docs surface**: `llms.txt`, skills, and the `@slexkit/mcp` read-only MCP server.\n\n## Packages\n\n| Package | Install | Contents |\n| --- | --- | --- |\n| `slexkit` | `npm install slexkit` | Runtime, Svelte components, ToolHost, styles |\n| `@slexkit/runtime` | `npm install slexkit @slexkit/runtime` | Component-free runtime wrapper |\n| `@slexkit/components-svelte` | `npm install slexkit @slexkit/runtime @slexkit/components-svelte` | Svelte component registration |\n| `@slexkit/theme-shadcn` | `npm install @slexkit/theme-shadcn` | CSS theme tokens |\n| `@slexkit/streamdown` | `npm install slexkit @slexkit/theme-shadcn @slexkit/streamdown streamdown react react-dom` | React / Streamdown Markdown renderer |\n| `@slexkit/mcp` | `npx -y @slexkit/mcp` | Read-only MCP server for docs, examples, and source validation |\n\nSee [Package Boundaries](site/content/reference/packages/en-US.md) for details.\n\n## Integrations\n\n| Host | Path |\n| --- | --- |\n| Browser DOM | `mount()`, `ingest()`, `boot()`, `disposeNamespace()` |\n| Markdown renderers | `createSlexKitMarkdownRuntimeHost()` |\n| React / Streamdown | `@slexkit/streamdown` |\n| Obsidian | Install **SlexKit** from Community Plugins; release repo: <https://github.com/slexkit/obsidian-slexkit> |\n| AI agents | `@slexkit/mcp`, `llms.txt`, SlexKit skill docs |\n| Custom components | `register()`, `registerSvelteComponent()`, `registerSubset()` |\n\n## Security Runtime\n\nTrusted mode runs inside the host realm and is intended for application-authored or reviewed source. Secure mode isolates untrusted Slex source in a sandbox iframe with an opaque origin, nonce-based CSP, locked-down globals, host-mediated network access, and a heartbeat watchdog.\n\nRead the [Security Runtime](site/content/reference/security/en-US.md) docs before rendering unreviewed user or model output.\n\n## Documentation\n\n| Document | Topic |\n| --- | --- |\n| [Getting Started](site/content/guides/quick-start/en-US.md) | Install and render a first Markdown-friendly Slex source |\n| [Integration](site/content/guides/integration/en-US.md) | Streamdown, Obsidian, and custom host paths |\n| [Runtime model](site/content/reference/runtime/en-US.md) | Mounting, updates, namespace store, lifecycle |\n| [Slex usage reference](site/content/reference/usage/en-US.md) | Source structure, directives, expressions, events, custom components |\n| [Security runtime](site/content/reference/security/en-US.md) | Threat model, sandbox iframe, policy, postMessage bridge |\n| [Slex Specification](site/content/reference/spec/en-US.md) | Protocol v0.1, types, merge rules, lifecycle hooks |\n| [ToolHost](site/content/reference/toolhost/en-US.md) | Tool-call rendering and custom templates |\n| [Icon system](site/content/reference/icons/en-US.md) | Phosphor icons, custom registration, Iconify fallback |\n| [AI / Agents](site/content/guides/ai-agents/en-US.md) | `llms.txt`, MCP server, skills, and authoring rules |\n| [Changelog](CHANGELOG.md) | Release notes and notable changes |\n\n## Version Information\n\n```ts\nimport { SLEXKIT_VERSION, SLEX_PROTOCOL_VERSION, getSlexKitInfo } from \"slexkit\";\n```\n\nThe npm package version, component implementation version, and Slex protocol version are exposed separately. The current public protocol is `v0.1`.\n\n## License\n\nMIT",
|
|
60
|
+
"hash": "4c55b5dc"
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
"id": "guides/intro",
|
|
@@ -738,8 +738,8 @@
|
|
|
738
738
|
"href": "/docs/releases/changelog",
|
|
739
739
|
"rawHref": "/docs/releases/changelog.md",
|
|
740
740
|
"sourcePath": "site/content/releases/changelog/en-US.md",
|
|
741
|
-
"body": "---\ntitle: Changelog\ncategory: Releases\nstatus: ready\norder: 10\nsummary: \"Release notes and notable changes for SlexKit.\"\nslexkitRenderMode: component\n---\n\n# Changelog\n\nAll notable changes to SlexKit.\n\n## v0.3.1 - Host stability and control rendering hardening\n\n### Added\n- Runtime style safety tests that block broad `:has()` selectors, `clip-path`, and slider track regressions in shipped CSS.\n- Regression coverage for disabled Switch, Checkbox, and Radio state attributes.\n\n### Changed\n- CI now installs dependencies with `bun install --frozen-lockfile` and runs lint before tests.\n- Disabled Switch, Checkbox, and Radio styling now uses explicit `data-disabled` attributes instead of broad relational selectors.\n- Select and sr-only helper styles avoid `clip-path` for better host and Obsidian CSS compatibility.\n\n### Fixed\n- Slider thumb rendering artifacts caused by painting the range track on the native input box.\n- Input focus visibility after removing custom engineering steppers.\n- Home RC example input labels now use native Input component labels instead of separate text labels.\n- Stat cards no longer clip updated text during cross-document state examples.\n- Markdown calculator examples no longer render duplicate section labels.\n\n## v0.3.0 - Examples overhaul with component audit and i18n\n\n### Added\n- Example gallery: 17 high-quality examples organized by usage scenario (Getting Started, Calculators, Data Browsing, Dashboards, Config Wizards, Decision Support, Platform Features)\n- English translations for all 17 example pages\n- `toolhost-demo`: real `renderToolCall` API with chat-style conversation UI\n- Example rendering infrastructure: `site/routes/examples.js`, `site/pages/examples.slex.js`, `site/data/examples.js`\n- Formula component (`src/components/svelte/content/Formula.svelte`) with KaTeX rendering\n- `src/engine/capabilities.ts`: structured capability docs for AI agents\n- `src/engine/validation.ts`: SPEC contract validation\n- `src/engine/stdlib.ts`: standard library with `math.clamp`, `math.safeDivide`, and other utilities\n- `src/engine/sandbox-runner.ts`: sandbox runner for secure runtime\n- Component state eval context shadowing test suite (`component-state-shadowing.test.ts`)\n- Collapsible and Callout double-rendering regression tests\n- Slider component name shadowing regression test\n\n### Changed\n- Examples reduced from 64 to 17 high-quality examples, organized by user story\n- Example source locale: `zh-CN` (with `en-US` translations)\n- `renderChildren` (`helpers.ts`) now clears existing content when children are present\n- Switch component now accepts `checked`/`value` props for initialization consistency with Checkbox\n- Site UI: DocsShell, DocRail, router, shell improvements\n- Components: Input, Select, Tabs, Table, PlaygroundMarkdown refinements\n- CSS: theme-shadcn, text-input, docs-shell styling updates\n\n### Fixed\n- Eval context shadowing: component names `g` and `api` no longer overwrite reserved context keys\n- `renderChildren` double rendering in Collapsible and Callout\n- Voltage divider summary typo (\"输入输入电压\")\n- Salary calculator fallback numbers to match actual calculator output\n- Tabs-and-branching: title and length conversion mismatch\n- 4 pre-existing test failures (ai-docs, page-structure, theme, markdown-content)\n\n### Removed\n- 47 low-quality/duplicate examples (reduced from 64 to 17)\n- Dead \"Fallback\" copywriting from all example files\n- Unused `DialogShell.svelte` component\n\n## v0.2.0 - First public release\n\n### Added\n- `@slexkit/mcp`: AI Agent Model Context Protocol server with `slexkitDocs`, `slexkitExamples`, `slexkitValidate` tools\n- Protocol marker: `\"slex\": \"0.1\"` required on all Slex expressions and ToolHost templates\n- SPEC contract validation: component specs are now validated against the runtime contract\n- Version sync automation (`scripts/sync-version.ts`) and changelog sync (`scripts/sync-changelog.ts`)\n- AI documentation generation pipeline with structured LLM-friendly output\n- Static site export with SEO metadata engine (`site/data/seo.js`, `site/scripts/export-static.ts`)\n- Chinese documentation for all reference and guide pages\n- Enhanced component state management with lifecycle hooks (`onMount`, `onUnmount`, `onUpdate`)\n\n### Changed\n- Switch component migrated from `checked` to `enabled` state mode\n- Documentation: restructured site content, synced en-US with zh-CN, added reference section\n- Theme: refined select styling, dropdown shadows, footer and info tone polish\n- AI docs generation enhanced with Chinese/English locale awareness\n\n### Fixed\n- Component spec alignment with documentation across all 28 components\n- Site routing and code block highlighting\n- Introduction and quick-start guide wording for clarity\n- Broken links and factual errors in component and reference documentation\n\n## v0.1.9\n\n### Added\n- Icon manager with Phosphor icon system (`registerIcon`, `registerIcons`, `getIcon`, `loadIcon`)\n- Expanded icon support across labeled components (badge, button, callout, etc.)\n- Icon docs page with registration API reference\n\n### Fixed\n- Refined component interactions in static site export\n- Tabs indicator animation restored\n- Callout and toast icon placement in titles\n- Numeric value display formatting\n\n### Changed\n- Site docs shell refactored for static export\n- Site navigation and theme controls alignment\n- Slex naming standardized across codebase\n\n## v0.1.8\n\n### Added\n- CSP-hardened secure runtime sandbox with heartbeat watchdog\n- `mountSecureArtifact()` for isolated iframe rendering\n- `createSlexKitMarkdownRuntimeHost()` for Markdown-hosted SlexKit blocks\n- Streamdown React renderer (`@slexkit/streamdown`)\n- Obsidian plugin adapter (`@slexkit/obsidian`)\n- Shadcn-compatible CSS theme (`@slexkit/theme-shadcn`)\n- Package boundary wrappers (`@slexkit/runtime`, `@slexkit/components-svelte`)\n- ToolHost with built-in templates: `confirm-action`, `choose-options`, `fill-form`\n\n### Changed\n- Component registration model: side-effect import registers all components\n- Styles reorganized into per-component CSS files\n- Build system: Bun.build with Svelte plugin, split ESM entries\n\n## v0.1.7\n\n### Added\n- `$for` list rendering with keyed reconciliation (delete / add-update-reorder / trim phases)\n- `$if` conditional rendering with enter/leave animation support\n- `$key` strategy: `$value`, property-based, or fallback to index\n- Component instance state modes: `value`, `checked`, `enabled`, `readable`, `none`\n- Lifecycle hooks: `g.onMount_<name>()`, `g.onUnmount_<name>()`, `g.onUpdate_<name>()`\n- Engineering number input with SI prefix parsing\n- Rich error diagnostics with line/column/excerpt display\n\n### Changed\n- Expression evaluation: `new Function()` compilation with reactive dependency tracking\n- Layout tree renderer now supports three rendering paths (normal, `$if`, `$for`)\n- `g` deep-merge preserves keys not present in the new state\n\n## v0.1.6 and earlier\n\n### Added\n- Reactive `g`/`layout` split with expression pipes (`$` read-pipes, `on*` write-pipes)\n- Custom fine-grained reactivity system (~280 lines, no external dependency)\n- Component registry with extensible renderer interface\n- Svelte 5 component adapter (creates stores from props, flushSync DOM)\n- `mount()`, `ingest()`, `boot()` entry points\n- 28 built-in Svelte components across 8 categories\n- `parseSlexSource()` DSL parser with `diagnoseSlexKitSource()` error reporting\n- Documentation site with interactive playground",
|
|
742
|
-
"hash": "
|
|
741
|
+
"body": "---\ntitle: Changelog\ncategory: Releases\nstatus: ready\norder: 10\nsummary: \"Release notes and notable changes for SlexKit.\"\nslexkitRenderMode: component\n---\n\n# Changelog\n\nAll notable changes to SlexKit.\n\n## v0.3.2 - Host CSS isolation and repeated layout hardening\n\n### Changed\n- `$for` rendering now uses comment anchors and direct child insertion instead of a wrapper element that depended on `display: contents`.\n- Site-only mobile navigation CSS moved out of the runtime base stylesheet and into the documentation site shell.\n- Component accessors now share one reactive effect across subscribers instead of creating duplicate subscriber fan-out work.\n\n### Fixed\n- Obsidian and other Markdown hosts no longer need to rewrite `$for` wrapper CSS to avoid `display: contents`, preserving grid and row layouts for repeated items.\n- Published runtime base CSS no longer leaks `#mobileNav` or `body[data-mobile-nav-open]` selectors into host pages.\n- Custom renderers that return no element no longer leave invalid `$for` slots behind during diffing or cleanup.\n\n## v0.3.1 - Host stability and control rendering hardening\n\n### Added\n- Runtime style safety tests that block broad `:has()` selectors, `clip-path`, and slider track regressions in shipped CSS.\n- Regression coverage for disabled Switch, Checkbox, and Radio state attributes.\n\n### Changed\n- CI now installs dependencies with `bun install --frozen-lockfile` and runs lint before tests.\n- Disabled Switch, Checkbox, and Radio styling now uses explicit `data-disabled` attributes instead of broad relational selectors.\n- Select and sr-only helper styles avoid `clip-path` for better host and Obsidian CSS compatibility.\n\n### Fixed\n- Slider thumb rendering artifacts caused by painting the range track on the native input box.\n- Input focus visibility after removing custom engineering steppers.\n- Home RC example input labels now use native Input component labels instead of separate text labels.\n- Stat cards no longer clip updated text during cross-document state examples.\n- Markdown calculator examples no longer render duplicate section labels.\n\n## v0.3.0 - Examples overhaul with component audit and i18n\n\n### Added\n- Example gallery: 17 high-quality examples organized by usage scenario (Getting Started, Calculators, Data Browsing, Dashboards, Config Wizards, Decision Support, Platform Features)\n- English translations for all 17 example pages\n- `toolhost-demo`: real `renderToolCall` API with chat-style conversation UI\n- Example rendering infrastructure: `site/routes/examples.js`, `site/pages/examples.slex.js`, `site/data/examples.js`\n- Formula component (`src/components/svelte/content/Formula.svelte`) with KaTeX rendering\n- `src/engine/capabilities.ts`: structured capability docs for AI agents\n- `src/engine/validation.ts`: SPEC contract validation\n- `src/engine/stdlib.ts`: standard library with `math.clamp`, `math.safeDivide`, and other utilities\n- `src/engine/sandbox-runner.ts`: sandbox runner for secure runtime\n- Component state eval context shadowing test suite (`component-state-shadowing.test.ts`)\n- Collapsible and Callout double-rendering regression tests\n- Slider component name shadowing regression test\n\n### Changed\n- Examples reduced from 64 to 17 high-quality examples, organized by user story\n- Example source locale: `zh-CN` (with `en-US` translations)\n- `renderChildren` (`helpers.ts`) now clears existing content when children are present\n- Switch component now accepts `checked`/`value` props for initialization consistency with Checkbox\n- Site UI: DocsShell, DocRail, router, shell improvements\n- Components: Input, Select, Tabs, Table, PlaygroundMarkdown refinements\n- CSS: theme-shadcn, text-input, docs-shell styling updates\n\n### Fixed\n- Eval context shadowing: component names `g` and `api` no longer overwrite reserved context keys\n- `renderChildren` double rendering in Collapsible and Callout\n- Voltage divider summary typo (\"输入输入电压\")\n- Salary calculator fallback numbers to match actual calculator output\n- Tabs-and-branching: title and length conversion mismatch\n- 4 pre-existing test failures (ai-docs, page-structure, theme, markdown-content)\n\n### Removed\n- 47 low-quality/duplicate examples (reduced from 64 to 17)\n- Dead \"Fallback\" copywriting from all example files\n- Unused `DialogShell.svelte` component\n\n## v0.2.0 - First public release\n\n### Added\n- `@slexkit/mcp`: AI Agent Model Context Protocol server with `slexkitDocs`, `slexkitExamples`, `slexkitValidate` tools\n- Protocol marker: `\"slex\": \"0.1\"` required on all Slex expressions and ToolHost templates\n- SPEC contract validation: component specs are now validated against the runtime contract\n- Version sync automation (`scripts/sync-version.ts`) and changelog sync (`scripts/sync-changelog.ts`)\n- AI documentation generation pipeline with structured LLM-friendly output\n- Static site export with SEO metadata engine (`site/data/seo.js`, `site/scripts/export-static.ts`)\n- Chinese documentation for all reference and guide pages\n- Enhanced component state management with lifecycle hooks (`onMount`, `onUnmount`, `onUpdate`)\n\n### Changed\n- Switch component migrated from `checked` to `enabled` state mode\n- Documentation: restructured site content, synced en-US with zh-CN, added reference section\n- Theme: refined select styling, dropdown shadows, footer and info tone polish\n- AI docs generation enhanced with Chinese/English locale awareness\n\n### Fixed\n- Component spec alignment with documentation across all 28 components\n- Site routing and code block highlighting\n- Introduction and quick-start guide wording for clarity\n- Broken links and factual errors in component and reference documentation\n\n## v0.1.9\n\n### Added\n- Icon manager with Phosphor icon system (`registerIcon`, `registerIcons`, `getIcon`, `loadIcon`)\n- Expanded icon support across labeled components (badge, button, callout, etc.)\n- Icon docs page with registration API reference\n\n### Fixed\n- Refined component interactions in static site export\n- Tabs indicator animation restored\n- Callout and toast icon placement in titles\n- Numeric value display formatting\n\n### Changed\n- Site docs shell refactored for static export\n- Site navigation and theme controls alignment\n- Slex naming standardized across codebase\n\n## v0.1.8\n\n### Added\n- CSP-hardened secure runtime sandbox with heartbeat watchdog\n- `mountSecureArtifact()` for isolated iframe rendering\n- `createSlexKitMarkdownRuntimeHost()` for Markdown-hosted SlexKit blocks\n- Streamdown React renderer (`@slexkit/streamdown`)\n- Obsidian plugin adapter (`@slexkit/obsidian`)\n- Shadcn-compatible CSS theme (`@slexkit/theme-shadcn`)\n- Package boundary wrappers (`@slexkit/runtime`, `@slexkit/components-svelte`)\n- ToolHost with built-in templates: `confirm-action`, `choose-options`, `fill-form`\n\n### Changed\n- Component registration model: side-effect import registers all components\n- Styles reorganized into per-component CSS files\n- Build system: Bun.build with Svelte plugin, split ESM entries\n\n## v0.1.7\n\n### Added\n- `$for` list rendering with keyed reconciliation (delete / add-update-reorder / trim phases)\n- `$if` conditional rendering with enter/leave animation support\n- `$key` strategy: `$value`, property-based, or fallback to index\n- Component instance state modes: `value`, `checked`, `enabled`, `readable`, `none`\n- Lifecycle hooks: `g.onMount_<name>()`, `g.onUnmount_<name>()`, `g.onUpdate_<name>()`\n- Engineering number input with SI prefix parsing\n- Rich error diagnostics with line/column/excerpt display\n\n### Changed\n- Expression evaluation: `new Function()` compilation with reactive dependency tracking\n- Layout tree renderer now supports three rendering paths (normal, `$if`, `$for`)\n- `g` deep-merge preserves keys not present in the new state\n\n## v0.1.6 and earlier\n\n### Added\n- Reactive `g`/`layout` split with expression pipes (`$` read-pipes, `on*` write-pipes)\n- Custom fine-grained reactivity system (~280 lines, no external dependency)\n- Component registry with extensible renderer interface\n- Svelte 5 component adapter (creates stores from props, flushSync DOM)\n- `mount()`, `ingest()`, `boot()` entry points\n- 28 built-in Svelte components across 8 categories\n- `parseSlexSource()` DSL parser with `diagnoseSlexKitSource()` error reporting\n- Documentation site with interactive playground",
|
|
742
|
+
"hash": "57cc5d83"
|
|
743
743
|
}
|
|
744
744
|
],
|
|
745
745
|
"expressionContext": [
|
|
@@ -3481,7 +3481,7 @@
|
|
|
3481
3481
|
}
|
|
3482
3482
|
],
|
|
3483
3483
|
"sourceHashes": {
|
|
3484
|
-
"README.md": "
|
|
3484
|
+
"README.md": "4c55b5dc",
|
|
3485
3485
|
"site/content/guides/intro/en-US.md": "bff82366",
|
|
3486
3486
|
"site/content/guides/quick-start/en-US.md": "ba82b030",
|
|
3487
3487
|
"site/content/guides/integration/en-US.md": "1138bddd",
|
|
@@ -3514,7 +3514,7 @@
|
|
|
3514
3514
|
"site/content/reference/toolhost/en-US.md": "f62ba8aa",
|
|
3515
3515
|
"site/content/reference/icons/en-US.md": "3d32cbbf",
|
|
3516
3516
|
"site/content/reference/rationale/en-US.md": "dcf53947",
|
|
3517
|
-
"site/content/releases/changelog/en-US.md": "
|
|
3517
|
+
"site/content/releases/changelog/en-US.md": "57cc5d83",
|
|
3518
3518
|
"site/content/components/accordion/en-US.md": "9e90867f",
|
|
3519
3519
|
"site/content/components/badge/en-US.md": "fb8275e7",
|
|
3520
3520
|
"site/content/components/button/en-US.md": "30463322",
|
package/dist/base.css
CHANGED
|
@@ -133,52 +133,6 @@ color-scheme: dark;
|
|
|
133
133
|
box-sizing: border-box;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
body[data-mobile-nav-open] {
|
|
137
|
-
overflow: hidden;
|
|
138
|
-
overscroll-behavior: contain;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
#mobileNav {
|
|
142
|
-
--mobile-nav-backdrop-opacity: 0;
|
|
143
|
-
--mobile-nav-panel-translate: -100%;
|
|
144
|
-
pointer-events: none;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
#mobileNav[data-open="true"] {
|
|
148
|
-
--mobile-nav-backdrop-opacity: 1;
|
|
149
|
-
--mobile-nav-panel-translate: 0px;
|
|
150
|
-
pointer-events: auto;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
#mobileNav [data-mobile-nav-backdrop] {
|
|
154
|
-
opacity: var(--mobile-nav-backdrop-opacity);
|
|
155
|
-
touch-action: pan-y;
|
|
156
|
-
transition: opacity 180ms ease;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
#mobileNav [data-mobile-nav-panel] {
|
|
160
|
-
transform: translateX(var(--mobile-nav-panel-translate));
|
|
161
|
-
touch-action: pan-y;
|
|
162
|
-
transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
163
|
-
will-change: transform;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
#mobileNav[data-dragging="true"] [data-mobile-nav-backdrop],
|
|
167
|
-
#mobileNav[data-dragging="true"] [data-mobile-nav-panel] {
|
|
168
|
-
transition: none;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@media (prefers-reduced-motion: reduce) {
|
|
172
|
-
#mobileNav [data-mobile-nav-backdrop],
|
|
173
|
-
#mobileNav [data-mobile-nav-panel] {
|
|
174
|
-
transition: none;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.slexkit-for-wrapper {
|
|
179
|
-
display: contents;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
136
|
.slexkit-source-toolbar {
|
|
183
137
|
display: flex;
|
|
184
138
|
align-items: center;
|
package/dist/runtime.cjs
CHANGED
|
@@ -468,19 +468,31 @@ function configureComponentScope(options) {
|
|
|
468
468
|
function createComponentAccessor(read) {
|
|
469
469
|
const subscribers = new Set;
|
|
470
470
|
let current = read();
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
471
|
+
let stopEffect;
|
|
472
|
+
const start = () => {
|
|
473
|
+
if (stopEffect)
|
|
474
|
+
return;
|
|
475
|
+
stopEffect = createEffect(() => {
|
|
476
476
|
current = read();
|
|
477
|
-
for (const subscriber of subscribers)
|
|
477
|
+
for (const subscriber of Array.from(subscribers))
|
|
478
478
|
subscriber(current);
|
|
479
479
|
flushDom?.();
|
|
480
480
|
});
|
|
481
|
+
};
|
|
482
|
+
const accessor = () => current;
|
|
483
|
+
accessor.subscribe = (run) => {
|
|
484
|
+
const wasIdle = subscribers.size === 0;
|
|
485
|
+
subscribers.add(run);
|
|
486
|
+
if (wasIdle)
|
|
487
|
+
start();
|
|
488
|
+
else
|
|
489
|
+
run(current);
|
|
481
490
|
return () => {
|
|
482
491
|
subscribers.delete(run);
|
|
483
|
-
|
|
492
|
+
if (subscribers.size === 0) {
|
|
493
|
+
stopEffect?.();
|
|
494
|
+
stopEffect = undefined;
|
|
495
|
+
}
|
|
484
496
|
};
|
|
485
497
|
};
|
|
486
498
|
return accessor;
|
|
@@ -1331,9 +1343,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1331
1343
|
const renderer = getRenderer(type);
|
|
1332
1344
|
if (!renderer)
|
|
1333
1345
|
return;
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
|
|
1346
|
+
const doc = container.ownerDocument || document;
|
|
1347
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1348
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1349
|
+
container.append(startAnchor, endAnchor);
|
|
1337
1350
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1338
1351
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1339
1352
|
const $keyProp = props.$key;
|
|
@@ -1346,8 +1359,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1346
1359
|
disposedSlots.add(slot);
|
|
1347
1360
|
leavingSlots.delete(slot);
|
|
1348
1361
|
callHook(g, name, "onUnmount");
|
|
1349
|
-
|
|
1350
|
-
|
|
1362
|
+
if (slot.el) {
|
|
1363
|
+
disposeComponent(slot.el);
|
|
1364
|
+
slot.el.remove();
|
|
1365
|
+
}
|
|
1351
1366
|
if (slot.dispose)
|
|
1352
1367
|
slot.dispose();
|
|
1353
1368
|
};
|
|
@@ -1372,12 +1387,16 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1372
1387
|
}
|
|
1373
1388
|
}
|
|
1374
1389
|
for (const slot of deletedSlots) {
|
|
1375
|
-
container.appendChild(slot.el);
|
|
1376
1390
|
leavingSlots.add(slot);
|
|
1391
|
+
if (!slot.el) {
|
|
1392
|
+
disposeSlot(slot);
|
|
1393
|
+
continue;
|
|
1394
|
+
}
|
|
1377
1395
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1378
1396
|
disposeSlot(slot);
|
|
1379
1397
|
});
|
|
1380
1398
|
}
|
|
1399
|
+
let cursor = startAnchor;
|
|
1381
1400
|
arr.forEach((item, index) => {
|
|
1382
1401
|
item = asReactiveValue(item, g);
|
|
1383
1402
|
const keyVal = newKeys[index];
|
|
@@ -1405,20 +1424,22 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1405
1424
|
const indexSignal = createSignal(index);
|
|
1406
1425
|
const revisionSignal = createSignal(0);
|
|
1407
1426
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1408
|
-
if (slot.el) {
|
|
1409
|
-
|
|
1410
|
-
|
|
1427
|
+
if (!slot.el) {
|
|
1428
|
+
disposeSlot(slot);
|
|
1429
|
+
return;
|
|
1411
1430
|
}
|
|
1431
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1432
|
+
callHook(g, name, "onMount");
|
|
1412
1433
|
slotMap.set(keyVal, slot);
|
|
1413
1434
|
}
|
|
1414
|
-
const
|
|
1415
|
-
if (slot.el &&
|
|
1416
|
-
|
|
1435
|
+
const nextChild = cursor.nextSibling;
|
|
1436
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1437
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1438
|
+
}
|
|
1439
|
+
if (slot.el) {
|
|
1440
|
+
cursor = slot.el;
|
|
1417
1441
|
}
|
|
1418
1442
|
});
|
|
1419
|
-
while (forWrapper.children.length > arr.length) {
|
|
1420
|
-
forWrapper.lastChild.remove();
|
|
1421
|
-
}
|
|
1422
1443
|
});
|
|
1423
1444
|
onCleanup(() => {
|
|
1424
1445
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1426,7 +1447,8 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1426
1447
|
slotMap.clear();
|
|
1427
1448
|
for (const slot of Array.from(leavingSlots))
|
|
1428
1449
|
disposeSlot(slot);
|
|
1429
|
-
|
|
1450
|
+
startAnchor.remove();
|
|
1451
|
+
endAnchor.remove();
|
|
1430
1452
|
});
|
|
1431
1453
|
}
|
|
1432
1454
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1803,7 +1825,7 @@ ${parseSource}
|
|
|
1803
1825
|
var parseSlexKitDsl = parseSlexSource;
|
|
1804
1826
|
|
|
1805
1827
|
// src/version.ts
|
|
1806
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1828
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1807
1829
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1808
1830
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1809
1831
|
function getSlexKitInfo() {
|
package/dist/runtime.js
CHANGED
|
@@ -396,19 +396,31 @@ function configureComponentScope(options) {
|
|
|
396
396
|
function createComponentAccessor(read) {
|
|
397
397
|
const subscribers = new Set;
|
|
398
398
|
let current = read();
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
399
|
+
let stopEffect;
|
|
400
|
+
const start = () => {
|
|
401
|
+
if (stopEffect)
|
|
402
|
+
return;
|
|
403
|
+
stopEffect = createEffect(() => {
|
|
404
404
|
current = read();
|
|
405
|
-
for (const subscriber of subscribers)
|
|
405
|
+
for (const subscriber of Array.from(subscribers))
|
|
406
406
|
subscriber(current);
|
|
407
407
|
flushDom?.();
|
|
408
408
|
});
|
|
409
|
+
};
|
|
410
|
+
const accessor = () => current;
|
|
411
|
+
accessor.subscribe = (run) => {
|
|
412
|
+
const wasIdle = subscribers.size === 0;
|
|
413
|
+
subscribers.add(run);
|
|
414
|
+
if (wasIdle)
|
|
415
|
+
start();
|
|
416
|
+
else
|
|
417
|
+
run(current);
|
|
409
418
|
return () => {
|
|
410
419
|
subscribers.delete(run);
|
|
411
|
-
|
|
420
|
+
if (subscribers.size === 0) {
|
|
421
|
+
stopEffect?.();
|
|
422
|
+
stopEffect = undefined;
|
|
423
|
+
}
|
|
412
424
|
};
|
|
413
425
|
};
|
|
414
426
|
return accessor;
|
|
@@ -1259,9 +1271,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1259
1271
|
const renderer = getRenderer(type);
|
|
1260
1272
|
if (!renderer)
|
|
1261
1273
|
return;
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1274
|
+
const doc = container.ownerDocument || document;
|
|
1275
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1276
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1277
|
+
container.append(startAnchor, endAnchor);
|
|
1265
1278
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1266
1279
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1267
1280
|
const $keyProp = props.$key;
|
|
@@ -1274,8 +1287,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1274
1287
|
disposedSlots.add(slot);
|
|
1275
1288
|
leavingSlots.delete(slot);
|
|
1276
1289
|
callHook(g, name, "onUnmount");
|
|
1277
|
-
|
|
1278
|
-
|
|
1290
|
+
if (slot.el) {
|
|
1291
|
+
disposeComponent(slot.el);
|
|
1292
|
+
slot.el.remove();
|
|
1293
|
+
}
|
|
1279
1294
|
if (slot.dispose)
|
|
1280
1295
|
slot.dispose();
|
|
1281
1296
|
};
|
|
@@ -1300,12 +1315,16 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1300
1315
|
}
|
|
1301
1316
|
}
|
|
1302
1317
|
for (const slot of deletedSlots) {
|
|
1303
|
-
container.appendChild(slot.el);
|
|
1304
1318
|
leavingSlots.add(slot);
|
|
1319
|
+
if (!slot.el) {
|
|
1320
|
+
disposeSlot(slot);
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1305
1323
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1306
1324
|
disposeSlot(slot);
|
|
1307
1325
|
});
|
|
1308
1326
|
}
|
|
1327
|
+
let cursor = startAnchor;
|
|
1309
1328
|
arr.forEach((item, index) => {
|
|
1310
1329
|
item = asReactiveValue(item, g);
|
|
1311
1330
|
const keyVal = newKeys[index];
|
|
@@ -1333,20 +1352,22 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1333
1352
|
const indexSignal = createSignal(index);
|
|
1334
1353
|
const revisionSignal = createSignal(0);
|
|
1335
1354
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1336
|
-
if (slot.el) {
|
|
1337
|
-
|
|
1338
|
-
|
|
1355
|
+
if (!slot.el) {
|
|
1356
|
+
disposeSlot(slot);
|
|
1357
|
+
return;
|
|
1339
1358
|
}
|
|
1359
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1360
|
+
callHook(g, name, "onMount");
|
|
1340
1361
|
slotMap.set(keyVal, slot);
|
|
1341
1362
|
}
|
|
1342
|
-
const
|
|
1343
|
-
if (slot.el &&
|
|
1344
|
-
|
|
1363
|
+
const nextChild = cursor.nextSibling;
|
|
1364
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1365
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1366
|
+
}
|
|
1367
|
+
if (slot.el) {
|
|
1368
|
+
cursor = slot.el;
|
|
1345
1369
|
}
|
|
1346
1370
|
});
|
|
1347
|
-
while (forWrapper.children.length > arr.length) {
|
|
1348
|
-
forWrapper.lastChild.remove();
|
|
1349
|
-
}
|
|
1350
1371
|
});
|
|
1351
1372
|
onCleanup(() => {
|
|
1352
1373
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1354,7 +1375,8 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1354
1375
|
slotMap.clear();
|
|
1355
1376
|
for (const slot of Array.from(leavingSlots))
|
|
1356
1377
|
disposeSlot(slot);
|
|
1357
|
-
|
|
1378
|
+
startAnchor.remove();
|
|
1379
|
+
endAnchor.remove();
|
|
1358
1380
|
});
|
|
1359
1381
|
}
|
|
1360
1382
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1731,7 +1753,7 @@ ${parseSource}
|
|
|
1731
1753
|
var parseSlexKitDsl = parseSlexSource;
|
|
1732
1754
|
|
|
1733
1755
|
// src/version.ts
|
|
1734
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1756
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1735
1757
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1736
1758
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1737
1759
|
function getSlexKitInfo() {
|
package/dist/slexkit.cjs
CHANGED
|
@@ -490,19 +490,31 @@ function configureComponentScope(options) {
|
|
|
490
490
|
function createComponentAccessor(read) {
|
|
491
491
|
const subscribers = new Set;
|
|
492
492
|
let current = read();
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
493
|
+
let stopEffect;
|
|
494
|
+
const start = () => {
|
|
495
|
+
if (stopEffect)
|
|
496
|
+
return;
|
|
497
|
+
stopEffect = createEffect(() => {
|
|
498
498
|
current = read();
|
|
499
|
-
for (const subscriber of subscribers)
|
|
499
|
+
for (const subscriber of Array.from(subscribers))
|
|
500
500
|
subscriber(current);
|
|
501
501
|
flushDom?.();
|
|
502
502
|
});
|
|
503
|
+
};
|
|
504
|
+
const accessor = () => current;
|
|
505
|
+
accessor.subscribe = (run) => {
|
|
506
|
+
const wasIdle = subscribers.size === 0;
|
|
507
|
+
subscribers.add(run);
|
|
508
|
+
if (wasIdle)
|
|
509
|
+
start();
|
|
510
|
+
else
|
|
511
|
+
run(current);
|
|
503
512
|
return () => {
|
|
504
513
|
subscribers.delete(run);
|
|
505
|
-
|
|
514
|
+
if (subscribers.size === 0) {
|
|
515
|
+
stopEffect?.();
|
|
516
|
+
stopEffect = undefined;
|
|
517
|
+
}
|
|
506
518
|
};
|
|
507
519
|
};
|
|
508
520
|
return accessor;
|
|
@@ -1353,9 +1365,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1353
1365
|
const renderer = getRenderer(type);
|
|
1354
1366
|
if (!renderer)
|
|
1355
1367
|
return;
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1368
|
+
const doc = container.ownerDocument || document;
|
|
1369
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1370
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1371
|
+
container.append(startAnchor, endAnchor);
|
|
1359
1372
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1360
1373
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1361
1374
|
const $keyProp = props.$key;
|
|
@@ -1368,8 +1381,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1368
1381
|
disposedSlots.add(slot);
|
|
1369
1382
|
leavingSlots.delete(slot);
|
|
1370
1383
|
callHook(g, name, "onUnmount");
|
|
1371
|
-
|
|
1372
|
-
|
|
1384
|
+
if (slot.el) {
|
|
1385
|
+
disposeComponent(slot.el);
|
|
1386
|
+
slot.el.remove();
|
|
1387
|
+
}
|
|
1373
1388
|
if (slot.dispose)
|
|
1374
1389
|
slot.dispose();
|
|
1375
1390
|
};
|
|
@@ -1394,12 +1409,16 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1394
1409
|
}
|
|
1395
1410
|
}
|
|
1396
1411
|
for (const slot of deletedSlots) {
|
|
1397
|
-
container.appendChild(slot.el);
|
|
1398
1412
|
leavingSlots.add(slot);
|
|
1413
|
+
if (!slot.el) {
|
|
1414
|
+
disposeSlot(slot);
|
|
1415
|
+
continue;
|
|
1416
|
+
}
|
|
1399
1417
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1400
1418
|
disposeSlot(slot);
|
|
1401
1419
|
});
|
|
1402
1420
|
}
|
|
1421
|
+
let cursor = startAnchor;
|
|
1403
1422
|
arr.forEach((item, index) => {
|
|
1404
1423
|
item = asReactiveValue(item, g);
|
|
1405
1424
|
const keyVal = newKeys[index];
|
|
@@ -1427,20 +1446,22 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1427
1446
|
const indexSignal = createSignal(index);
|
|
1428
1447
|
const revisionSignal = createSignal(0);
|
|
1429
1448
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1430
|
-
if (slot.el) {
|
|
1431
|
-
|
|
1432
|
-
|
|
1449
|
+
if (!slot.el) {
|
|
1450
|
+
disposeSlot(slot);
|
|
1451
|
+
return;
|
|
1433
1452
|
}
|
|
1453
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1454
|
+
callHook(g, name, "onMount");
|
|
1434
1455
|
slotMap.set(keyVal, slot);
|
|
1435
1456
|
}
|
|
1436
|
-
const
|
|
1437
|
-
if (slot.el &&
|
|
1438
|
-
|
|
1457
|
+
const nextChild = cursor.nextSibling;
|
|
1458
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1459
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1460
|
+
}
|
|
1461
|
+
if (slot.el) {
|
|
1462
|
+
cursor = slot.el;
|
|
1439
1463
|
}
|
|
1440
1464
|
});
|
|
1441
|
-
while (forWrapper.children.length > arr.length) {
|
|
1442
|
-
forWrapper.lastChild.remove();
|
|
1443
|
-
}
|
|
1444
1465
|
});
|
|
1445
1466
|
onCleanup(() => {
|
|
1446
1467
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1448,7 +1469,8 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1448
1469
|
slotMap.clear();
|
|
1449
1470
|
for (const slot of Array.from(leavingSlots))
|
|
1450
1471
|
disposeSlot(slot);
|
|
1451
|
-
|
|
1472
|
+
startAnchor.remove();
|
|
1473
|
+
endAnchor.remove();
|
|
1452
1474
|
});
|
|
1453
1475
|
}
|
|
1454
1476
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1825,7 +1847,7 @@ ${parseSource}
|
|
|
1825
1847
|
var parseSlexKitDsl = parseSlexSource;
|
|
1826
1848
|
|
|
1827
1849
|
// src/version.ts
|
|
1828
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1850
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1829
1851
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1830
1852
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1831
1853
|
function getSlexKitInfo() {
|
package/dist/slexkit.css
CHANGED
|
@@ -904,52 +904,6 @@ color-scheme: dark;
|
|
|
904
904
|
box-sizing: border-box;
|
|
905
905
|
}
|
|
906
906
|
|
|
907
|
-
body[data-mobile-nav-open] {
|
|
908
|
-
overflow: hidden;
|
|
909
|
-
overscroll-behavior: contain;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
#mobileNav {
|
|
913
|
-
--mobile-nav-backdrop-opacity: 0;
|
|
914
|
-
--mobile-nav-panel-translate: -100%;
|
|
915
|
-
pointer-events: none;
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
#mobileNav[data-open="true"] {
|
|
919
|
-
--mobile-nav-backdrop-opacity: 1;
|
|
920
|
-
--mobile-nav-panel-translate: 0px;
|
|
921
|
-
pointer-events: auto;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
#mobileNav [data-mobile-nav-backdrop] {
|
|
925
|
-
opacity: var(--mobile-nav-backdrop-opacity);
|
|
926
|
-
touch-action: pan-y;
|
|
927
|
-
transition: opacity 180ms ease;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
#mobileNav [data-mobile-nav-panel] {
|
|
931
|
-
transform: translateX(var(--mobile-nav-panel-translate));
|
|
932
|
-
touch-action: pan-y;
|
|
933
|
-
transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
934
|
-
will-change: transform;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
#mobileNav[data-dragging="true"] [data-mobile-nav-backdrop],
|
|
938
|
-
#mobileNav[data-dragging="true"] [data-mobile-nav-panel] {
|
|
939
|
-
transition: none;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
@media (prefers-reduced-motion: reduce) {
|
|
943
|
-
#mobileNav [data-mobile-nav-backdrop],
|
|
944
|
-
#mobileNav [data-mobile-nav-panel] {
|
|
945
|
-
transition: none;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
.slexkit-for-wrapper {
|
|
950
|
-
display: contents;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
907
|
.slexkit-source-toolbar {
|
|
954
908
|
display: flex;
|
|
955
909
|
align-items: center;
|
package/dist/slexkit.js
CHANGED
|
@@ -396,19 +396,31 @@ function configureComponentScope(options) {
|
|
|
396
396
|
function createComponentAccessor(read) {
|
|
397
397
|
const subscribers = new Set;
|
|
398
398
|
let current = read();
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
399
|
+
let stopEffect;
|
|
400
|
+
const start = () => {
|
|
401
|
+
if (stopEffect)
|
|
402
|
+
return;
|
|
403
|
+
stopEffect = createEffect(() => {
|
|
404
404
|
current = read();
|
|
405
|
-
for (const subscriber of subscribers)
|
|
405
|
+
for (const subscriber of Array.from(subscribers))
|
|
406
406
|
subscriber(current);
|
|
407
407
|
flushDom?.();
|
|
408
408
|
});
|
|
409
|
+
};
|
|
410
|
+
const accessor = () => current;
|
|
411
|
+
accessor.subscribe = (run) => {
|
|
412
|
+
const wasIdle = subscribers.size === 0;
|
|
413
|
+
subscribers.add(run);
|
|
414
|
+
if (wasIdle)
|
|
415
|
+
start();
|
|
416
|
+
else
|
|
417
|
+
run(current);
|
|
409
418
|
return () => {
|
|
410
419
|
subscribers.delete(run);
|
|
411
|
-
|
|
420
|
+
if (subscribers.size === 0) {
|
|
421
|
+
stopEffect?.();
|
|
422
|
+
stopEffect = undefined;
|
|
423
|
+
}
|
|
412
424
|
};
|
|
413
425
|
};
|
|
414
426
|
return accessor;
|
|
@@ -1259,9 +1271,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1259
1271
|
const renderer = getRenderer(type);
|
|
1260
1272
|
if (!renderer)
|
|
1261
1273
|
return;
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1274
|
+
const doc = container.ownerDocument || document;
|
|
1275
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1276
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1277
|
+
container.append(startAnchor, endAnchor);
|
|
1265
1278
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1266
1279
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1267
1280
|
const $keyProp = props.$key;
|
|
@@ -1274,8 +1287,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1274
1287
|
disposedSlots.add(slot);
|
|
1275
1288
|
leavingSlots.delete(slot);
|
|
1276
1289
|
callHook(g, name, "onUnmount");
|
|
1277
|
-
|
|
1278
|
-
|
|
1290
|
+
if (slot.el) {
|
|
1291
|
+
disposeComponent(slot.el);
|
|
1292
|
+
slot.el.remove();
|
|
1293
|
+
}
|
|
1279
1294
|
if (slot.dispose)
|
|
1280
1295
|
slot.dispose();
|
|
1281
1296
|
};
|
|
@@ -1300,12 +1315,16 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1300
1315
|
}
|
|
1301
1316
|
}
|
|
1302
1317
|
for (const slot of deletedSlots) {
|
|
1303
|
-
container.appendChild(slot.el);
|
|
1304
1318
|
leavingSlots.add(slot);
|
|
1319
|
+
if (!slot.el) {
|
|
1320
|
+
disposeSlot(slot);
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1305
1323
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1306
1324
|
disposeSlot(slot);
|
|
1307
1325
|
});
|
|
1308
1326
|
}
|
|
1327
|
+
let cursor = startAnchor;
|
|
1309
1328
|
arr.forEach((item, index) => {
|
|
1310
1329
|
item = asReactiveValue(item, g);
|
|
1311
1330
|
const keyVal = newKeys[index];
|
|
@@ -1333,20 +1352,22 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1333
1352
|
const indexSignal = createSignal(index);
|
|
1334
1353
|
const revisionSignal = createSignal(0);
|
|
1335
1354
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1336
|
-
if (slot.el) {
|
|
1337
|
-
|
|
1338
|
-
|
|
1355
|
+
if (!slot.el) {
|
|
1356
|
+
disposeSlot(slot);
|
|
1357
|
+
return;
|
|
1339
1358
|
}
|
|
1359
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1360
|
+
callHook(g, name, "onMount");
|
|
1340
1361
|
slotMap.set(keyVal, slot);
|
|
1341
1362
|
}
|
|
1342
|
-
const
|
|
1343
|
-
if (slot.el &&
|
|
1344
|
-
|
|
1363
|
+
const nextChild = cursor.nextSibling;
|
|
1364
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1365
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1366
|
+
}
|
|
1367
|
+
if (slot.el) {
|
|
1368
|
+
cursor = slot.el;
|
|
1345
1369
|
}
|
|
1346
1370
|
});
|
|
1347
|
-
while (forWrapper.children.length > arr.length) {
|
|
1348
|
-
forWrapper.lastChild.remove();
|
|
1349
|
-
}
|
|
1350
1371
|
});
|
|
1351
1372
|
onCleanup(() => {
|
|
1352
1373
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1354,7 +1375,8 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1354
1375
|
slotMap.clear();
|
|
1355
1376
|
for (const slot of Array.from(leavingSlots))
|
|
1356
1377
|
disposeSlot(slot);
|
|
1357
|
-
|
|
1378
|
+
startAnchor.remove();
|
|
1379
|
+
endAnchor.remove();
|
|
1358
1380
|
});
|
|
1359
1381
|
}
|
|
1360
1382
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1731,7 +1753,7 @@ ${parseSource}
|
|
|
1731
1753
|
var parseSlexKitDsl = parseSlexSource;
|
|
1732
1754
|
|
|
1733
1755
|
// src/version.ts
|
|
1734
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1756
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1735
1757
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1736
1758
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1737
1759
|
function getSlexKitInfo() {
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export declare const SLEXKIT_VERSION = "0.3.
|
|
1
|
+
export declare const SLEXKIT_VERSION = "0.3.2";
|
|
2
2
|
export declare const SLEX_PROTOCOL_VERSION = "0.1";
|
|
3
|
-
export declare const SLEXKIT_COMPONENTS_VERSION = "0.3.
|
|
3
|
+
export declare const SLEXKIT_COMPONENTS_VERSION = "0.3.2";
|
|
4
4
|
export declare function getSlexKitInfo(): {
|
|
5
5
|
version: string;
|
|
6
6
|
protocolVersion: string;
|
|
@@ -493,19 +493,31 @@
|
|
|
493
493
|
function createComponentAccessor(read) {
|
|
494
494
|
const subscribers = new Set;
|
|
495
495
|
let current = read();
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
496
|
+
let stopEffect;
|
|
497
|
+
const start = () => {
|
|
498
|
+
if (stopEffect)
|
|
499
|
+
return;
|
|
500
|
+
stopEffect = createEffect(() => {
|
|
501
501
|
current = read();
|
|
502
|
-
for (const subscriber of subscribers)
|
|
502
|
+
for (const subscriber of Array.from(subscribers))
|
|
503
503
|
subscriber(current);
|
|
504
504
|
flushDom?.();
|
|
505
505
|
});
|
|
506
|
+
};
|
|
507
|
+
const accessor = () => current;
|
|
508
|
+
accessor.subscribe = (run) => {
|
|
509
|
+
const wasIdle = subscribers.size === 0;
|
|
510
|
+
subscribers.add(run);
|
|
511
|
+
if (wasIdle)
|
|
512
|
+
start();
|
|
513
|
+
else
|
|
514
|
+
run(current);
|
|
506
515
|
return () => {
|
|
507
516
|
subscribers.delete(run);
|
|
508
|
-
|
|
517
|
+
if (subscribers.size === 0) {
|
|
518
|
+
stopEffect?.();
|
|
519
|
+
stopEffect = undefined;
|
|
520
|
+
}
|
|
509
521
|
};
|
|
510
522
|
};
|
|
511
523
|
return accessor;
|
|
@@ -1356,9 +1368,10 @@
|
|
|
1356
1368
|
const renderer = getRenderer(type);
|
|
1357
1369
|
if (!renderer)
|
|
1358
1370
|
return;
|
|
1359
|
-
const
|
|
1360
|
-
|
|
1361
|
-
|
|
1371
|
+
const doc = container.ownerDocument || document;
|
|
1372
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1373
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1374
|
+
container.append(startAnchor, endAnchor);
|
|
1362
1375
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1363
1376
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1364
1377
|
const $keyProp = props.$key;
|
|
@@ -1371,8 +1384,10 @@
|
|
|
1371
1384
|
disposedSlots.add(slot);
|
|
1372
1385
|
leavingSlots.delete(slot);
|
|
1373
1386
|
callHook(g, name, "onUnmount");
|
|
1374
|
-
|
|
1375
|
-
|
|
1387
|
+
if (slot.el) {
|
|
1388
|
+
disposeComponent(slot.el);
|
|
1389
|
+
slot.el.remove();
|
|
1390
|
+
}
|
|
1376
1391
|
if (slot.dispose)
|
|
1377
1392
|
slot.dispose();
|
|
1378
1393
|
};
|
|
@@ -1397,12 +1412,16 @@
|
|
|
1397
1412
|
}
|
|
1398
1413
|
}
|
|
1399
1414
|
for (const slot of deletedSlots) {
|
|
1400
|
-
container.appendChild(slot.el);
|
|
1401
1415
|
leavingSlots.add(slot);
|
|
1416
|
+
if (!slot.el) {
|
|
1417
|
+
disposeSlot(slot);
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1402
1420
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1403
1421
|
disposeSlot(slot);
|
|
1404
1422
|
});
|
|
1405
1423
|
}
|
|
1424
|
+
let cursor = startAnchor;
|
|
1406
1425
|
arr.forEach((item, index) => {
|
|
1407
1426
|
item = asReactiveValue(item, g);
|
|
1408
1427
|
const keyVal = newKeys[index];
|
|
@@ -1430,20 +1449,22 @@
|
|
|
1430
1449
|
const indexSignal = createSignal(index);
|
|
1431
1450
|
const revisionSignal = createSignal(0);
|
|
1432
1451
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1433
|
-
if (slot.el) {
|
|
1434
|
-
|
|
1435
|
-
|
|
1452
|
+
if (!slot.el) {
|
|
1453
|
+
disposeSlot(slot);
|
|
1454
|
+
return;
|
|
1436
1455
|
}
|
|
1456
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1457
|
+
callHook(g, name, "onMount");
|
|
1437
1458
|
slotMap.set(keyVal, slot);
|
|
1438
1459
|
}
|
|
1439
|
-
const
|
|
1440
|
-
if (slot.el &&
|
|
1441
|
-
|
|
1460
|
+
const nextChild = cursor.nextSibling;
|
|
1461
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1462
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1463
|
+
}
|
|
1464
|
+
if (slot.el) {
|
|
1465
|
+
cursor = slot.el;
|
|
1442
1466
|
}
|
|
1443
1467
|
});
|
|
1444
|
-
while (forWrapper.children.length > arr.length) {
|
|
1445
|
-
forWrapper.lastChild.remove();
|
|
1446
|
-
}
|
|
1447
1468
|
});
|
|
1448
1469
|
onCleanup(() => {
|
|
1449
1470
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1451,7 +1472,8 @@
|
|
|
1451
1472
|
slotMap.clear();
|
|
1452
1473
|
for (const slot of Array.from(leavingSlots))
|
|
1453
1474
|
disposeSlot(slot);
|
|
1454
|
-
|
|
1475
|
+
startAnchor.remove();
|
|
1476
|
+
endAnchor.remove();
|
|
1455
1477
|
});
|
|
1456
1478
|
}
|
|
1457
1479
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
package/dist/umd/slexkit.umd.js
CHANGED
|
@@ -499,19 +499,31 @@
|
|
|
499
499
|
function createComponentAccessor(read) {
|
|
500
500
|
const subscribers = new Set;
|
|
501
501
|
let current = read();
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
502
|
+
let stopEffect;
|
|
503
|
+
const start = () => {
|
|
504
|
+
if (stopEffect)
|
|
505
|
+
return;
|
|
506
|
+
stopEffect = createEffect(() => {
|
|
507
507
|
current = read();
|
|
508
|
-
for (const subscriber of subscribers)
|
|
508
|
+
for (const subscriber of Array.from(subscribers))
|
|
509
509
|
subscriber(current);
|
|
510
510
|
flushDom?.();
|
|
511
511
|
});
|
|
512
|
+
};
|
|
513
|
+
const accessor = () => current;
|
|
514
|
+
accessor.subscribe = (run) => {
|
|
515
|
+
const wasIdle = subscribers.size === 0;
|
|
516
|
+
subscribers.add(run);
|
|
517
|
+
if (wasIdle)
|
|
518
|
+
start();
|
|
519
|
+
else
|
|
520
|
+
run(current);
|
|
512
521
|
return () => {
|
|
513
522
|
subscribers.delete(run);
|
|
514
|
-
|
|
523
|
+
if (subscribers.size === 0) {
|
|
524
|
+
stopEffect?.();
|
|
525
|
+
stopEffect = undefined;
|
|
526
|
+
}
|
|
515
527
|
};
|
|
516
528
|
};
|
|
517
529
|
return accessor;
|
|
@@ -1362,9 +1374,10 @@
|
|
|
1362
1374
|
const renderer = getRenderer(type);
|
|
1363
1375
|
if (!renderer)
|
|
1364
1376
|
return;
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
|
|
1377
|
+
const doc = container.ownerDocument || document;
|
|
1378
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1379
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1380
|
+
container.append(startAnchor, endAnchor);
|
|
1368
1381
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1369
1382
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1370
1383
|
const $keyProp = props.$key;
|
|
@@ -1377,8 +1390,10 @@
|
|
|
1377
1390
|
disposedSlots.add(slot);
|
|
1378
1391
|
leavingSlots.delete(slot);
|
|
1379
1392
|
callHook(g, name, "onUnmount");
|
|
1380
|
-
|
|
1381
|
-
|
|
1393
|
+
if (slot.el) {
|
|
1394
|
+
disposeComponent(slot.el);
|
|
1395
|
+
slot.el.remove();
|
|
1396
|
+
}
|
|
1382
1397
|
if (slot.dispose)
|
|
1383
1398
|
slot.dispose();
|
|
1384
1399
|
};
|
|
@@ -1403,12 +1418,16 @@
|
|
|
1403
1418
|
}
|
|
1404
1419
|
}
|
|
1405
1420
|
for (const slot of deletedSlots) {
|
|
1406
|
-
container.appendChild(slot.el);
|
|
1407
1421
|
leavingSlots.add(slot);
|
|
1422
|
+
if (!slot.el) {
|
|
1423
|
+
disposeSlot(slot);
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1408
1426
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1409
1427
|
disposeSlot(slot);
|
|
1410
1428
|
});
|
|
1411
1429
|
}
|
|
1430
|
+
let cursor = startAnchor;
|
|
1412
1431
|
arr.forEach((item, index) => {
|
|
1413
1432
|
item = asReactiveValue(item, g);
|
|
1414
1433
|
const keyVal = newKeys[index];
|
|
@@ -1436,20 +1455,22 @@
|
|
|
1436
1455
|
const indexSignal = createSignal(index);
|
|
1437
1456
|
const revisionSignal = createSignal(0);
|
|
1438
1457
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1439
|
-
if (slot.el) {
|
|
1440
|
-
|
|
1441
|
-
|
|
1458
|
+
if (!slot.el) {
|
|
1459
|
+
disposeSlot(slot);
|
|
1460
|
+
return;
|
|
1442
1461
|
}
|
|
1462
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1463
|
+
callHook(g, name, "onMount");
|
|
1443
1464
|
slotMap.set(keyVal, slot);
|
|
1444
1465
|
}
|
|
1445
|
-
const
|
|
1446
|
-
if (slot.el &&
|
|
1447
|
-
|
|
1466
|
+
const nextChild = cursor.nextSibling;
|
|
1467
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1468
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1469
|
+
}
|
|
1470
|
+
if (slot.el) {
|
|
1471
|
+
cursor = slot.el;
|
|
1448
1472
|
}
|
|
1449
1473
|
});
|
|
1450
|
-
while (forWrapper.children.length > arr.length) {
|
|
1451
|
-
forWrapper.lastChild.remove();
|
|
1452
|
-
}
|
|
1453
1474
|
});
|
|
1454
1475
|
onCleanup(() => {
|
|
1455
1476
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1457,7 +1478,8 @@
|
|
|
1457
1478
|
slotMap.clear();
|
|
1458
1479
|
for (const slot of Array.from(leavingSlots))
|
|
1459
1480
|
disposeSlot(slot);
|
|
1460
|
-
|
|
1481
|
+
startAnchor.remove();
|
|
1482
|
+
endAnchor.remove();
|
|
1461
1483
|
});
|
|
1462
1484
|
}
|
|
1463
1485
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1834,7 +1856,7 @@ ${parseSource}
|
|
|
1834
1856
|
var parseSlexKitDsl = parseSlexSource;
|
|
1835
1857
|
|
|
1836
1858
|
// src/version.ts
|
|
1837
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1859
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1838
1860
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1839
1861
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1840
1862
|
function getSlexKitInfo() {
|
package/package.json
CHANGED
package/src/styles/layout.css
CHANGED
|
@@ -32,52 +32,6 @@
|
|
|
32
32
|
box-sizing: border-box;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
body[data-mobile-nav-open] {
|
|
36
|
-
overflow: hidden;
|
|
37
|
-
overscroll-behavior: contain;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
#mobileNav {
|
|
41
|
-
--mobile-nav-backdrop-opacity: 0;
|
|
42
|
-
--mobile-nav-panel-translate: -100%;
|
|
43
|
-
pointer-events: none;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
#mobileNav[data-open="true"] {
|
|
47
|
-
--mobile-nav-backdrop-opacity: 1;
|
|
48
|
-
--mobile-nav-panel-translate: 0px;
|
|
49
|
-
pointer-events: auto;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
#mobileNav [data-mobile-nav-backdrop] {
|
|
53
|
-
opacity: var(--mobile-nav-backdrop-opacity);
|
|
54
|
-
touch-action: pan-y;
|
|
55
|
-
transition: opacity 180ms ease;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#mobileNav [data-mobile-nav-panel] {
|
|
59
|
-
transform: translateX(var(--mobile-nav-panel-translate));
|
|
60
|
-
touch-action: pan-y;
|
|
61
|
-
transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
62
|
-
will-change: transform;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
#mobileNav[data-dragging="true"] [data-mobile-nav-backdrop],
|
|
66
|
-
#mobileNav[data-dragging="true"] [data-mobile-nav-panel] {
|
|
67
|
-
transition: none;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@media (prefers-reduced-motion: reduce) {
|
|
71
|
-
#mobileNav [data-mobile-nav-backdrop],
|
|
72
|
-
#mobileNav [data-mobile-nav-panel] {
|
|
73
|
-
transition: none;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.slexkit-for-wrapper {
|
|
78
|
-
display: contents;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
35
|
.slexkit-source-toolbar {
|
|
82
36
|
display: flex;
|
|
83
37
|
align-items: center;
|