@byscott-io/pagelet 0.0.0-stage → 0.2.0
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 +68 -0
- package/LICENSE +21 -0
- package/README.md +158 -2
- package/dist/editor.cjs +59 -0
- package/dist/editor.cjs.map +1 -0
- package/dist/editor.css +3214 -0
- package/dist/editor.js +57 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.cjs +946 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +922 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 (2026-11-13)
|
|
4
|
+
|
|
5
|
+
### npm `@byscott-io/pagelet`
|
|
6
|
+
- **Page settings** (the page's own fields): a browser title, and a background
|
|
7
|
+
that follows the site's, is custom, or is none, with an overlay color and
|
|
8
|
+
**opacity %**. `pageSettings(document)` returns the title.
|
|
9
|
+
- **Site background**, set in the theme: an image, overlay color and opacity,
|
|
10
|
+
`fit` (`cover`, or `photo` to show the whole photo), and `frame` (`none`, or
|
|
11
|
+
`card` for a bordered, rounded, padded frame).
|
|
12
|
+
- **New blocks:** Quote (italic text plus a citation), Icon list (icon, text, an
|
|
13
|
+
optional link), Schedule (rows of day / time / what), and Embedded page.
|
|
14
|
+
- **Embedded page** is offered only when the app names trusted hosts:
|
|
15
|
+
`createPalette({ embedHosts: ['example.org'] })`. https only, sandboxed.
|
|
16
|
+
- **Right alignment** for Text, Heading, Button and the new blocks; Image gains
|
|
17
|
+
alignment and a width %; Section gains a background image with an overlay
|
|
18
|
+
color and opacity.
|
|
19
|
+
- A built-in **icon set** (inline SVG): location, phone, email, video, calendar,
|
|
20
|
+
clock, link, Facebook, YouTube. `<Icon name>` is exported.
|
|
21
|
+
- **`<PageletMenu>` and `<PageletLayout>`:** a site's menu from its settings
|
|
22
|
+
(a brand logo, items with optional icon and highlight, left and right groups,
|
|
23
|
+
external links in a new tab, a menu button on narrow screens) and the frame
|
|
24
|
+
around a page. Pass your router's link component as `linkComponent`.
|
|
25
|
+
- The menu's brand link is a plain anchor for `tel:`/`mailto:` (like menu
|
|
26
|
+
items), never passed to the app's router.
|
|
27
|
+
- **Client:** `getSite`, `updateSite`, and `getPublishedPage(path)` returning
|
|
28
|
+
`{ document, pagePath, rest }`; `createPage`/`updatePage` take `matchesSubpaths`.
|
|
29
|
+
|
|
30
|
+
### gem `pagelet`
|
|
31
|
+
- **Site settings** per owner (`Pagelet::Site`): the theme and the menu.
|
|
32
|
+
`GET /site` is public; `PATCH /site` needs `:publish`, since changes are live
|
|
33
|
+
at once. Shapes are checked (menu style, labels, links, groups, size).
|
|
34
|
+
- **Pages that answer for sub-paths:** `matches_subpaths` on a page makes
|
|
35
|
+
`/messages` serve `/messages/43`. An exact page wins, then the longest such
|
|
36
|
+
prefix. `Page.published_match(owner, path)` returns the document, the page's
|
|
37
|
+
path and the remainder; `GET /published` returns them too.
|
|
38
|
+
- **New migration:** run `bin/rails pagelet:install:migrations` and migrate
|
|
39
|
+
(see docs/UPGRADING.md).
|
|
40
|
+
|
|
41
|
+
## 0.1.0 (2026-11-13)
|
|
42
|
+
|
|
43
|
+
First release.
|
|
44
|
+
|
|
45
|
+
### npm `@byscott-io/pagelet`
|
|
46
|
+
- `createPalette`: the built-in blocks plus an app's own, with hiding and grouping.
|
|
47
|
+
- `PageletPage`: renders a saved page. No editor code; works in server-side rendering.
|
|
48
|
+
- `PageletEditor` (from `@byscott-io/pagelet/editor`): the visual editor, built on Puck 0.24.
|
|
49
|
+
- Built-in blocks: Section, Columns, Spacer, Divider, Hero, Heading, Text, Button,
|
|
50
|
+
Call to action, Cards, FAQ, Image, Image with text, Video (YouTube/Vimeo).
|
|
51
|
+
- Theming through CSS variables.
|
|
52
|
+
- Versioned page documents (`{ pagelet: 1, data }`), upgraded when loaded.
|
|
53
|
+
- `safeUrl` / `safeImageUrl`: user-entered links and images refuse unsafe schemes.
|
|
54
|
+
- `createPageletClient`: the engine's API from the browser, with CSRF and
|
|
55
|
+
`PageletApiError` carrying the server's field errors.
|
|
56
|
+
|
|
57
|
+
### gem `pagelet` (Rails engine)
|
|
58
|
+
- Pages scoped to an owner the app supplies; another owner's page is a 404.
|
|
59
|
+
- Drafts, numbered published versions (never edited after publishing), and
|
|
60
|
+
rollback by restoring an old version into the draft.
|
|
61
|
+
- JSON API for the editor, behind the app's own `authorize` hook (`:edit`, `:publish`).
|
|
62
|
+
- `Page.published_document(owner, path)` for server-side rendering, and
|
|
63
|
+
`Page.sitemap_entries(owner)`. Drafts never reach either.
|
|
64
|
+
- Document checks: format version, shape, and a size limit.
|
|
65
|
+
- `bin/rails generate pagelet:install`: initializer, migrations, route.
|
|
66
|
+
|
|
67
|
+
## 0.0.1 (gem only)
|
|
68
|
+
- Placeholder that reserves the name on RubyGems. No functionality.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Scott Gibson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,159 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pagelet
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A page builder for React apps. Your users build pages by dragging blocks onto a
|
|
4
|
+
canvas, and your site draws the saved pages with the same React components.
|
|
5
|
+
|
|
6
|
+
- **A visual editor** for admin screens: drag, reorder, edit, undo, and preview
|
|
7
|
+
at phone and desktop widths.
|
|
8
|
+
- **A small renderer** for public pages. It has no editor code in it, and it
|
|
9
|
+
works in server-side rendering, so search engines see real HTML.
|
|
10
|
+
- **A standard set of blocks**: sections, columns, hero, headings, text,
|
|
11
|
+
quotes, icon lists, schedules, buttons, calls to action, cards, FAQ, images,
|
|
12
|
+
image with text, YouTube/Vimeo video, and (for hosts you allow) embedded pages.
|
|
13
|
+
- **Page backgrounds**: a site-wide photo under a panel of any color and
|
|
14
|
+
opacity, which each page can follow, replace or turn off.
|
|
15
|
+
- **Your own blocks**: register any React component and it appears in the
|
|
16
|
+
palette beside the built-in ones.
|
|
17
|
+
- **Theming** through CSS variables: colors, fonts, corner radius, page width.
|
|
18
|
+
- **A site menu and layout**: logo, items with icons and highlights, left and
|
|
19
|
+
right groups, and a menu button on phones, all from site settings.
|
|
20
|
+
|
|
21
|
+
pagelet is built on [Puck](https://puckeditor.com), an MIT-licensed visual
|
|
22
|
+
editor for React. Your app talks only to pagelet, which keeps Puck's upgrades in
|
|
23
|
+
one place.
|
|
24
|
+
|
|
25
|
+
> Not related to the older `pagelet` package on npm from the BigPipe project.
|
|
26
|
+
|
|
27
|
+
**Status:** early (0.1.x); the API may still change. Two packages:
|
|
28
|
+
|
|
29
|
+
- `@byscott-io/pagelet` (npm): the editor, renderer and blocks.
|
|
30
|
+
- `pagelet` (gem): a Rails engine that stores pages, keeps every published
|
|
31
|
+
version, and serves the editor's API. See [docs/INTEGRATION.md](docs/INTEGRATION.md).
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
yarn add @byscott-io/pagelet react react-dom
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Use
|
|
40
|
+
|
|
41
|
+
**1. Define your palette once**, with any blocks of your own:
|
|
42
|
+
|
|
43
|
+
```jsx
|
|
44
|
+
import { createPalette } from '@byscott-io/pagelet';
|
|
45
|
+
|
|
46
|
+
const Quote = {
|
|
47
|
+
label: 'Quote',
|
|
48
|
+
category: 'extras',
|
|
49
|
+
fields: { text: { type: 'textarea' }, author: { type: 'text' } },
|
|
50
|
+
render: ({ text, author }) => (
|
|
51
|
+
<blockquote>
|
|
52
|
+
{text}
|
|
53
|
+
<cite>{author}</cite>
|
|
54
|
+
</blockquote>
|
|
55
|
+
),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const palette = createPalette({
|
|
59
|
+
blocks: { Quote }, // added beside the built-in blocks
|
|
60
|
+
categories: { extras: { title: 'Extras' } },
|
|
61
|
+
hide: ['Faq'], // built-in blocks you don't want
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**2. Edit pages** in your admin screens:
|
|
66
|
+
|
|
67
|
+
```jsx
|
|
68
|
+
import { PageletEditor } from '@byscott-io/pagelet/editor';
|
|
69
|
+
import '@byscott-io/pagelet/editor.css';
|
|
70
|
+
|
|
71
|
+
<PageletEditor
|
|
72
|
+
document={savedDocument}
|
|
73
|
+
palette={palette}
|
|
74
|
+
theme={siteTheme}
|
|
75
|
+
headerTitle="Home page"
|
|
76
|
+
onPublish={(document) => save(document)}
|
|
77
|
+
/>;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**3. Render pages** on your site:
|
|
81
|
+
|
|
82
|
+
```jsx
|
|
83
|
+
import { PageletPage } from '@byscott-io/pagelet';
|
|
84
|
+
|
|
85
|
+
<PageletPage document={savedDocument} palette={palette} theme={siteTheme} />;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`document` is plain JSON (`{ pagelet: 1, data: {...} }`). Store it as-is; pass
|
|
89
|
+
it back to either component. Pages saved by an older pagelet are upgraded when
|
|
90
|
+
they load.
|
|
91
|
+
|
|
92
|
+
**4. With the Rails engine**, the client does the storing:
|
|
93
|
+
|
|
94
|
+
```jsx
|
|
95
|
+
import { createPageletClient } from '@byscott-io/pagelet';
|
|
96
|
+
|
|
97
|
+
const pages = createPageletClient(); // same origin, mounted at /pagelet
|
|
98
|
+
|
|
99
|
+
const { page } = await pages.getPage(id);
|
|
100
|
+
<PageletEditor
|
|
101
|
+
document={page.draft_document}
|
|
102
|
+
palette={palette}
|
|
103
|
+
onChange={(document) => pages.saveDraft(id, document)}
|
|
104
|
+
onPublish={async (document) => {
|
|
105
|
+
await pages.saveDraft(id, document);
|
|
106
|
+
await pages.publish(id);
|
|
107
|
+
}}
|
|
108
|
+
/>;
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
It sends the app's session cookie and the CSRF token from the page's
|
|
112
|
+
`csrf-token` meta tag, and throws `PageletApiError` (with `status` and field
|
|
113
|
+
`errors`) when the server refuses.
|
|
114
|
+
|
|
115
|
+
## Theme
|
|
116
|
+
|
|
117
|
+
Any subset of these tokens; the rest use the defaults:
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
{
|
|
121
|
+
colorText, colorBackground, colorMuted,
|
|
122
|
+
colorAccent, colorAccentText,
|
|
123
|
+
fontBody, fontHeading,
|
|
124
|
+
radius, maxWidth, space,
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
They become CSS variables (`--pagelet-color-accent`, …) on the page wrapper, so
|
|
129
|
+
your own blocks can use them too: `color: var(--pagelet-color-accent)`.
|
|
130
|
+
|
|
131
|
+
A site background goes in the theme too, and each page can follow it, use its
|
|
132
|
+
own, or have none (the page's Background setting):
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
background: {
|
|
136
|
+
image: '/images/building.jpg',
|
|
137
|
+
overlayColor: '#ffffff',
|
|
138
|
+
overlayOpacity: 85, // percent
|
|
139
|
+
fit: 'photo', // or 'cover'
|
|
140
|
+
frame: 'card', // or 'none'
|
|
141
|
+
rounded: true,
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Writing your own blocks
|
|
146
|
+
|
|
147
|
+
A block is a [Puck component config](https://puckeditor.com/docs/api-reference/configuration/component-config)
|
|
148
|
+
(`fields`, `defaultProps`, `render`) plus an optional `category`.
|
|
149
|
+
|
|
150
|
+
- **Render on the server.** `render` must not touch `window` or `document`
|
|
151
|
+
while rendering. Add browser-only behavior in an effect.
|
|
152
|
+
- **Treat every URL as untrusted.** Pass user-entered links through `safeUrl`
|
|
153
|
+
and images through `safeImageUrl` (both exported); they refuse `javascript:`
|
|
154
|
+
and other unsafe schemes.
|
|
155
|
+
- A block with a built-in block's name replaces that block.
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT. See [LICENSE](LICENSE).
|
package/dist/editor.cjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var core = require('@puckeditor/core');
|
|
5
|
+
var rsc = require('@puckeditor/core/rsc');
|
|
6
|
+
|
|
7
|
+
const DOCUMENT_VERSION = 1;
|
|
8
|
+
function emptyData() {
|
|
9
|
+
return { root: { props: {} }, content: [] };
|
|
10
|
+
}
|
|
11
|
+
function createDocument(data = emptyData()) {
|
|
12
|
+
return { pagelet: DOCUMENT_VERSION, data };
|
|
13
|
+
}
|
|
14
|
+
function upgradeDocument(document, palette) {
|
|
15
|
+
if (document == null) return createDocument();
|
|
16
|
+
if (typeof document !== "object") {
|
|
17
|
+
throw new TypeError("pagelet: a page document must be an object");
|
|
18
|
+
}
|
|
19
|
+
let doc = document;
|
|
20
|
+
if (!("pagelet" in doc)) {
|
|
21
|
+
if (!("content" in doc) && !("root" in doc)) {
|
|
22
|
+
throw new TypeError('pagelet: not a page document (no "pagelet" version and no Puck data)');
|
|
23
|
+
}
|
|
24
|
+
doc = createDocument(doc);
|
|
25
|
+
}
|
|
26
|
+
if (doc.pagelet > DOCUMENT_VERSION) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`pagelet: this page was saved by a newer pagelet (format ${doc.pagelet}); this version reads up to format ${DOCUMENT_VERSION}. Upgrade @byscott-io/pagelet.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
const data = { ...emptyData(), ...doc.data };
|
|
32
|
+
return createDocument(palette && needsPuckMigration(data) ? rsc.migrate(data, palette.config) : data);
|
|
33
|
+
}
|
|
34
|
+
function needsPuckMigration(data) {
|
|
35
|
+
const zones = data.zones ?? {};
|
|
36
|
+
if (Object.values(zones).some((content) => Array.isArray(content) && content.length > 0)) return true;
|
|
37
|
+
const root = data.root ?? {};
|
|
38
|
+
return Object.keys(root).some((key) => key !== "props" && key !== "readOnly");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function PageletEditor({ document, palette, theme, onPublish, onChange, headerTitle, ...rest }) {
|
|
42
|
+
if (!palette) throw new Error("pagelet: <PageletEditor> needs a palette (see createPalette)");
|
|
43
|
+
const { data } = upgradeDocument(document, palette);
|
|
44
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45
|
+
core.Puck,
|
|
46
|
+
{
|
|
47
|
+
...rest,
|
|
48
|
+
config: palette.config,
|
|
49
|
+
data,
|
|
50
|
+
metadata: { pageletTheme: theme },
|
|
51
|
+
headerTitle,
|
|
52
|
+
onPublish: onPublish ? (next) => onPublish(createDocument(next)) : void 0,
|
|
53
|
+
onChange: onChange ? (next) => onChange(createDocument(next)) : void 0
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.PageletEditor = PageletEditor;
|
|
59
|
+
//# sourceMappingURL=editor.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.cjs","sources":["../src/document.js","../src/PageletEditor.jsx"],"sourcesContent":["import { migrate } from '@puckeditor/core/rsc';\n\n// What an app stores for a page: Puck's data inside an envelope that carries\n// pagelet's own format version. The version lets a stored page be upgraded when\n// pagelet or Puck changes shape, so apps never hold raw Puck data whose format\n// they do not control.\nexport const DOCUMENT_VERSION = 1;\n\nexport function emptyData() {\n return { root: { props: {} }, content: [] };\n}\n\nexport function createDocument(data = emptyData()) {\n return { pagelet: DOCUMENT_VERSION, data };\n}\n\n// Bring a stored document up to the current format.\n//\n// Accepts bare Puck data too, since an app adopting pagelet may already hold\n// some. Passing the palette also runs Puck's own migrate(), which converts\n// older Puck structures (DropZone zones) into the current one (slots).\nexport function upgradeDocument(document, palette) {\n if (document == null) return createDocument();\n if (typeof document !== 'object') {\n throw new TypeError('pagelet: a page document must be an object');\n }\n\n let doc = document;\n if (!('pagelet' in doc)) {\n if (!('content' in doc) && !('root' in doc)) {\n throw new TypeError('pagelet: not a page document (no \"pagelet\" version and no Puck data)');\n }\n doc = createDocument(doc);\n }\n\n if (doc.pagelet > DOCUMENT_VERSION) {\n throw new Error(\n `pagelet: this page was saved by a newer pagelet (format ${doc.pagelet}); ` +\n `this version reads up to format ${DOCUMENT_VERSION}. Upgrade @byscott-io/pagelet.`,\n );\n }\n\n // Format migrations go here, one step per version:\n // if (doc.pagelet === 1) doc = migrateV1toV2(doc);\n\n const data = { ...emptyData(), ...doc.data };\n return createDocument(palette && needsPuckMigration(data) ? migrate(data, palette.config) : data);\n}\n\n// Puck's migrate() logs to the console every time it is given a config, even\n// when there is nothing to convert. On a public page that would be a log line\n// per page view, so only call it for data in an older Puck shape: DropZone\n// zones holding content, or a root whose fields sit outside `props`.\nexport function needsPuckMigration(data) {\n const zones = data.zones ?? {};\n if (Object.values(zones).some((content) => Array.isArray(content) && content.length > 0)) return true;\n const root = data.root ?? {};\n return Object.keys(root).some((key) => key !== 'props' && key !== 'readOnly');\n}\n\n// A page's own settings (title, background), for the app to use outside the\n// page body, e.g. the browser title.\nexport function pageSettings(document) {\n const props = upgradeDocument(document)?.data?.root?.props ?? {};\n return { title: props.title || '', background: props.background ?? 'site' };\n}\n","import { Puck } from '@puckeditor/core';\nimport { createDocument, upgradeDocument } from './document.js';\n\n// The visual editor. Import from \"@byscott-io/pagelet/editor\" (and its\n// stylesheet from \"@byscott-io/pagelet/editor.css\") in admin screens only.\n//\n// onPublish and onChange receive a pagelet document, ready to store as-is.\nexport function PageletEditor({ document, palette, theme, onPublish, onChange, headerTitle, ...rest }) {\n if (!palette) throw new Error('pagelet: <PageletEditor> needs a palette (see createPalette)');\n const { data } = upgradeDocument(document, palette);\n return (\n <Puck\n {...rest}\n config={palette.config}\n data={data}\n metadata={{ pageletTheme: theme }}\n headerTitle={headerTitle}\n onPublish={onPublish ? (next) => onPublish(createDocument(next)) : undefined}\n onChange={onChange ? (next) => onChange(createDocument(next)) : undefined}\n />\n );\n}\n"],"names":["migrate","jsx","Puck"],"mappings":";;;;;;AAMO,MAAM,gBAAA,GAAmB,CAAA;AAEzB,SAAS,SAAA,GAAY;AAC1B,EAAA,OAAO,EAAE,MAAM,EAAE,KAAA,EAAO,EAAC,EAAE,EAAG,OAAA,EAAS,EAAC,EAAE;AAC5C;AAEO,SAAS,cAAA,CAAe,IAAA,GAAO,SAAA,EAAU,EAAG;AACjD,EAAA,OAAO,EAAE,OAAA,EAAS,gBAAA,EAAkB,IAAA,EAAK;AAC3C;AAOO,SAAS,eAAA,CAAgB,UAAU,OAAA,EAAS;AACjD,EAAA,IAAI,QAAA,IAAY,IAAA,EAAM,OAAO,cAAA,EAAe;AAC5C,EAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,IAAA,MAAM,IAAI,UAAU,4CAA4C,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,GAAA,GAAM,QAAA;AACV,EAAA,IAAI,EAAE,aAAa,GAAA,CAAA,EAAM;AACvB,IAAA,IAAI,EAAE,SAAA,IAAa,GAAA,CAAA,IAAQ,EAAE,UAAU,GAAA,CAAA,EAAM;AAC3C,MAAA,MAAM,IAAI,UAAU,sEAAsE,CAAA;AAAA,IAC5F;AACA,IAAA,GAAA,GAAM,eAAe,GAAG,CAAA;AAAA,EAC1B;AAEA,EAAA,IAAI,GAAA,CAAI,UAAU,gBAAA,EAAkB;AAClC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,wDAAA,EAA2D,GAAA,CAAI,OAAO,CAAA,mCAAA,EACjC,gBAAgB,CAAA,8BAAA;AAAA,KACvD;AAAA,EACF;AAKA,EAAA,MAAM,OAAO,EAAE,GAAG,WAAU,EAAG,GAAG,IAAI,IAAA,EAAK;AAC3C,EAAA,OAAO,cAAA,CAAe,OAAA,IAAW,kBAAA,CAAmB,IAAI,CAAA,GAAIA,YAAQ,IAAA,EAAM,OAAA,CAAQ,MAAM,CAAA,GAAI,IAAI,CAAA;AAClG;AAMO,SAAS,mBAAmB,IAAA,EAAM;AACvC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,EAAC;AAC7B,EAAA,IAAI,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA,CAAE,KAAK,CAAC,OAAA,KAAY,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IAAK,OAAA,CAAQ,MAAA,GAAS,CAAC,GAAG,OAAO,IAAA;AACjG,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQ,EAAC;AAC3B,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,IAAA,CAAK,CAAC,GAAA,KAAQ,GAAA,KAAQ,OAAA,IAAW,GAAA,KAAQ,UAAU,CAAA;AAC9E;;ACnDO,SAAS,aAAA,CAAc,EAAE,QAAA,EAAU,OAAA,EAAS,KAAA,EAAO,WAAW,QAAA,EAAU,WAAA,EAAa,GAAG,IAAA,EAAK,EAAG;AACrG,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,MAAM,8DAA8D,CAAA;AAC5F,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,eAAA,CAAgB,UAAU,OAAO,CAAA;AAClD,EAAA,uBACEC,cAAA;AAAA,IAACC,SAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,IAAA;AAAA,MACA,QAAA,EAAU,EAAE,YAAA,EAAc,KAAA,EAAM;AAAA,MAChC,WAAA;AAAA,MACA,SAAA,EAAW,YAAY,CAAC,IAAA,KAAS,UAAU,cAAA,CAAe,IAAI,CAAC,CAAA,GAAI,MAAA;AAAA,MACnE,QAAA,EAAU,WAAW,CAAC,IAAA,KAAS,SAAS,cAAA,CAAe,IAAI,CAAC,CAAA,GAAI;AAAA;AAAA,GAClE;AAEJ;;"}
|