@threadlabs/looma 0.38.0 → 0.39.1
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/EXPRESSIVE-MARKDOWN.md +2 -0
- package/README.md +1 -1
- package/components/ui-skeleton/ui-skeleton.html +36 -7
- package/components/ui-skeleton/ui-skeleton.js +46 -0
- package/dist/index.js +13 -12
- package/docs/README.md +3 -3
- package/docs/catalog.json +9 -9
- package/docs/cli.mjs +1 -1
- package/docs/commands.mjs +2 -2
- package/docs/index.d.ts +3 -3
- package/docs/local-server.mjs +1 -1
- package/docs/site.mjs +6 -6
- package/editor/expressmark.js +12 -4
- package/package.json +6 -6
- package/styles/ui-skeleton.css +30 -5
- package/vanilla/UiSkeleton.js +5 -3
- package/vue/UiSkeleton.vue +71 -10
- package/vue/chunks/UiSkeleton.js +41 -9
- package/vue/components.css +30 -4
package/docs/README.md
CHANGED
|
@@ -12,12 +12,12 @@ In a project with a `package.json`, install Looma and its documentation tools:
|
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
14
|
pnpm add @threadlabs/looma @nextwebwg/html-next@1.0.0-alpha.69
|
|
15
|
-
pnpm add -D markupress
|
|
15
|
+
pnpm add -D 'markupress@>=0.10.0 <1' '@threadlabs/markupkit@>=0.2.0 <1' vite
|
|
16
16
|
pnpm exec looma-docs init --title "The Fellowship"
|
|
17
17
|
pnpm exec looma-docs dev
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Use the tool versions accepted by Looma's optional peer dependencies. Markupress 0.
|
|
20
|
+
Use the tool versions accepted by Looma's optional peer dependencies. Markupress 0.10 and later compatible 0.x releases supply the current documentation theme, including one appearance button that cycles Automatic, Light and Dark. Regular component imports do not load the documentation server. Vue and Tiptap remain optional; install them when your own authored documentation mounts the Vue editor.
|
|
21
21
|
|
|
22
22
|
Initialization creates three project-owned files:
|
|
23
23
|
|
|
@@ -44,7 +44,7 @@ pnpm exec looma-docs build
|
|
|
44
44
|
pnpm exec looma-docs preview
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
`build` produces a static
|
|
47
|
+
`build` produces a static MarkupKit site in the configured output directory. `preview` serves that output without a repository writer. All commands accept `--root`; `dev` and `preview` also accept `--port`.
|
|
48
48
|
|
|
49
49
|
## Name your local design system
|
|
50
50
|
|
package/docs/catalog.json
CHANGED
|
@@ -458,7 +458,7 @@
|
|
|
458
458
|
],
|
|
459
459
|
"schemaVersion": 1,
|
|
460
460
|
"package": "@threadlabs/looma",
|
|
461
|
-
"version": "0.
|
|
461
|
+
"version": "0.39.1",
|
|
462
462
|
"groups": [
|
|
463
463
|
{
|
|
464
464
|
"id": "layout",
|
|
@@ -20455,7 +20455,7 @@
|
|
|
20455
20455
|
"tag": "ui-skeleton",
|
|
20456
20456
|
"package": "@threadlabs/looma",
|
|
20457
20457
|
"root": "span",
|
|
20458
|
-
"description": "Reserve the shape of incoming content without announcing each placeholder. Text follows the surrounding line metrics; circles and rectangles stand in for avatars and media. Use one status message and aria-busy on the loading region, then replace the placeholders with real content. Keep existing content visible during refresh when possible.
|
|
20458
|
+
"description": "Reserve the shape of incoming content without announcing each placeholder. Text follows the surrounding line metrics; circles and rectangles stand in for avatars and media. Use one status message and aria-busy on the loading region, then replace the placeholders with real content. Keep existing content visible during refresh when possible. A broad shimmer sweeps across the placeholders together by default, continuously from left to right. Reduced-motion preferences always keep it static.",
|
|
20459
20459
|
"designTokens": {
|
|
20460
20460
|
"sources": [
|
|
20461
20461
|
"packages/looma/src/components/ui-skeleton/ui-skeleton.html"
|
|
@@ -20499,9 +20499,9 @@
|
|
|
20499
20499
|
{
|
|
20500
20500
|
"name": "animated",
|
|
20501
20501
|
"property": "animated",
|
|
20502
|
-
"description": "
|
|
20502
|
+
"description": "Moves a subtle highlight from left to right. On by default; pass false to keep it static. Reduced-motion preferences always disable the shimmer.",
|
|
20503
20503
|
"type": "boolean",
|
|
20504
|
-
"default":
|
|
20504
|
+
"default": true
|
|
20505
20505
|
},
|
|
20506
20506
|
{
|
|
20507
20507
|
"name": "height",
|
|
@@ -20533,9 +20533,9 @@
|
|
|
20533
20533
|
"properties": [
|
|
20534
20534
|
{
|
|
20535
20535
|
"name": "animated",
|
|
20536
|
-
"description": "
|
|
20536
|
+
"description": "Moves a subtle highlight from left to right. On by default; pass false to keep it static. Reduced-motion preferences always disable the shimmer.",
|
|
20537
20537
|
"type": "boolean",
|
|
20538
|
-
"default":
|
|
20538
|
+
"default": true
|
|
20539
20539
|
},
|
|
20540
20540
|
{
|
|
20541
20541
|
"name": "height",
|
|
@@ -20605,9 +20605,9 @@
|
|
|
20605
20605
|
{
|
|
20606
20606
|
"id": "@threadlabs/looma/ui-skeleton/04-animation",
|
|
20607
20607
|
"name": "04-animation",
|
|
20608
|
-
"title": "
|
|
20609
|
-
"description": "
|
|
20610
|
-
"markup": "<ui-stack gap=\"s\">\n <ui-
|
|
20608
|
+
"title": "Shared shimmer",
|
|
20609
|
+
"description": "One broad gradient stays fixed to the viewport, so every placeholder reveals the same moving highlight. It loops continuously and stops for reduced motion.",
|
|
20610
|
+
"markup": "<ui-stack gap=\"s\">\n <ui-cluster gap=\"s\">\n <ui-skeleton shape=\"circle\"></ui-skeleton>\n <ui-skeleton width=\"50%\"></ui-skeleton>\n </ui-cluster>\n <ui-skeleton shape=\"rectangle\" width=\"75%\" height=\"3rem\"></ui-skeleton>\n</ui-stack>",
|
|
20611
20611
|
"resizable": false,
|
|
20612
20612
|
"bindings": "",
|
|
20613
20613
|
"frameworks": {}
|
package/docs/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@ try {
|
|
|
6
6
|
const { values, positionals } = parseArgs({ allowPositionals: true, options: { root: { type: 'string' }, port: { type: 'string' }, title: { type: 'string' }, help: { type: 'boolean', short: 'h' } } });
|
|
7
7
|
const [command = 'help'] = positionals;
|
|
8
8
|
if (values.help || command === 'help') {
|
|
9
|
-
console.log('looma-docs init | dev | build | preview\n\n --root <project> Project directory\n --port <number> Local server port (default 3000)\n --title <name> Documentation title for init\n\nInstall the optional documentation peers: markupress, @
|
|
9
|
+
console.log('looma-docs init | dev | build | preview\n\n --root <project> Project directory\n --port <number> Local server port (default 3000)\n --title <name> Documentation title for init\n\nInstall the optional documentation peers: markupress, @threadlabs/markupkit and vite.');
|
|
10
10
|
} else {
|
|
11
11
|
const options = { ...(values.root ? { root: values.root } : {}), ...(values.title ? { title: values.title } : {}) };
|
|
12
12
|
if (values.port) { const port = Number(values.port); if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error('Port must be an integer from 0 to 65535.'); options.port = port; }
|
package/docs/commands.mjs
CHANGED
|
@@ -47,11 +47,11 @@ export async function buildProjectDocumentation({ root = process.cwd(), config,
|
|
|
47
47
|
}
|
|
48
48
|
export async function previewProjectDocumentation({ root = process.cwd(), config, port = 3000 } = {}) {
|
|
49
49
|
if (!config) ({ root, config } = await readConfiguration(root));
|
|
50
|
-
const { previewApplication } = await tool('@
|
|
50
|
+
const { previewApplication } = await tool('@threadlabs/markupkit', root);
|
|
51
51
|
return previewApplication({ root, outDir: config.outDir ?? '.looma/site', base: config.base ?? '/', host: '127.0.0.1', port });
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/**
|
|
54
|
+
/** MarkupKit serves the build; this local-only gateway adds the constrained repository writer. */
|
|
55
55
|
export async function devProjectDocumentation({ root = process.cwd(), config, catalog, port = 3000, onError = console.error } = {}) {
|
|
56
56
|
const configured = Boolean(config);
|
|
57
57
|
if (!config) ({ root, config } = await readConfiguration(root));
|
package/docs/index.d.ts
CHANGED
|
@@ -39,9 +39,9 @@ export function discoverComponents(input: DiscoveryRoot & { root: string }): Pro
|
|
|
39
39
|
export function mergeCatalogs(catalogs: DocumentationCatalog[], options?: { categories?: Record<string, string> }): DocumentationCatalog;
|
|
40
40
|
export function prepareDocumentation(input: DocumentationInput & { root: string }): Promise<DocumentationSite>;
|
|
41
41
|
export function buildDocumentation(input?: DocumentationInput): Promise<DocumentationBuild>;
|
|
42
|
-
/** Optional
|
|
43
|
-
export function documentationOptions(site: DocumentationSite): Promise<import('@
|
|
44
|
-
export function documentationPlugin(site: DocumentationSite): import('@
|
|
42
|
+
/** Optional MarkupKit integration; server tooling peers are loaded only when invoked. */
|
|
43
|
+
export function documentationOptions(site: DocumentationSite): Promise<import('@threadlabs/markupkit').ApplicationOptions>;
|
|
44
|
+
export function documentationPlugin(site: DocumentationSite): import('@threadlabs/markupkit').MarkupKitPlugin;
|
|
45
45
|
export function initializeDocumentation(input?: { root?: string; title?: string }): Promise<{ config: DocumentationConfiguration; files: string[]; applicationImport: string }>;
|
|
46
46
|
export function readConfiguration(root?: string): Promise<{ root: string; config: DocumentationConfiguration }>;
|
|
47
47
|
export function buildProjectDocumentation(input?: DocumentationInput): Promise<DocumentationBuild>;
|
package/docs/local-server.mjs
CHANGED
|
@@ -17,7 +17,7 @@ async function body(request) {
|
|
|
17
17
|
/** Local capabilities stay in the parent editor; opaque example frames receive only theme CSS. */
|
|
18
18
|
export async function serveLocalDocumentation({ upstream, store, base = '/', port = 0, onSaved = async () => {} }) {
|
|
19
19
|
const target = new URL(upstream);
|
|
20
|
-
if (target.protocol !== 'http:' || target.hostname !== '127.0.0.1') throw new Error('The documentation upstream must be a loopback
|
|
20
|
+
if (target.protocol !== 'http:' || target.hostname !== '127.0.0.1') throw new Error('The documentation upstream must be a loopback MarkupKit server.');
|
|
21
21
|
const capability = randomBytes(32).toString('hex');
|
|
22
22
|
let origin;
|
|
23
23
|
const json = (response, status, data) => {
|
package/docs/site.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { cacheDirectory, rejectSymlink, withBuildLock } from './workspace.mjs';
|
|
|
13
13
|
const own = name => fileURLToPath(new URL(name, import.meta.url));
|
|
14
14
|
/** Resolve import-only optional tooling peers in the consumer's ESM package scope. */
|
|
15
15
|
export async function tool(name, root) {
|
|
16
|
-
if (!['markupress', '@
|
|
16
|
+
if (!['markupress', '@threadlabs/markupkit', 'vite'].includes(name)) throw new Error(`Unknown documentation tool ${name}.`);
|
|
17
17
|
const directory = await cacheDirectory(root, 'tooling');
|
|
18
18
|
const file = path.join(directory, name.replaceAll('/', '-').replace('@', '') + '.mjs');
|
|
19
19
|
await rejectSymlink(file);
|
|
@@ -89,7 +89,7 @@ export async function prepareDocumentation({ root, config = {}, catalog }) {
|
|
|
89
89
|
for (const file of ['customizer.js', 'theme.mjs', 'theme-session.mjs', 'value-editors.mjs', 'palette.mjs', 'fonts.mjs']) await cp(own(file), path.join(generated, file));
|
|
90
90
|
const write = async (file, source) => { await mkdir(path.dirname(file), { recursive: true }); await writeFile(file, source); };
|
|
91
91
|
const examples = [];
|
|
92
|
-
//
|
|
92
|
+
// MarkupKit route groups retain their labels/order in navigation without changing public URLs.
|
|
93
93
|
const groupDirectories = new Map(combined.groups.map((group, index) => [group.id,
|
|
94
94
|
`${String(index + 1).padStart(2, '0')}.(${group.label.replace(/[\\/()]/g, '-')})`]));
|
|
95
95
|
const generatedReferences = new Set();
|
|
@@ -114,7 +114,7 @@ export async function prepareDocumentation({ root, config = {}, catalog }) {
|
|
|
114
114
|
const setup = path.join(previews, key + '.js');
|
|
115
115
|
const behavior = example.behavior;
|
|
116
116
|
await write(setup, `import { connect as connectPreview } from '../preview.js';\n${behavior ? `import setupExample from ${JSON.stringify(behavior)};\n` : ''}export function connect(host) { const stopPreview = connectPreview(host); ${behavior ? 'const stopExample = setupExample(host.element);' : ''} return () => { ${behavior ? 'stopExample?.();' : ''} stopPreview(); }; }\n`);
|
|
117
|
-
await write(file, ` ${links}\n<template component="looma-preview-${key}" module="./${key}.js"><defs><meta name="
|
|
117
|
+
await write(file, ` ${links}\n<template component="looma-preview-${key}" module="./${key}.js"><defs><meta name="mk:navigation" content="hidden"><title>${escapeHtml(example.title)}</title></defs><div data-preview="${escapeHtml(example.id)}"${component.group === 'layout' ? ' data-preview-layout' : ''}>${example.markup}${anchors}</div></template>\n`);
|
|
118
118
|
examples.push({ ...example, file, component: component.id, path: base + previewPath(example).slice(1) });
|
|
119
119
|
}
|
|
120
120
|
}
|
|
@@ -155,7 +155,7 @@ export async function prepareDocumentation({ root, config = {}, catalog }) {
|
|
|
155
155
|
return { root, config, base, catalog: combined, examples, generated, content, previews, redirects };
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
/** Bundle validated theme restoration into
|
|
158
|
+
/** Bundle validated theme restoration into MarkupKit's before-paint head hook. */
|
|
159
159
|
async function themeBootstrap(site) {
|
|
160
160
|
const { build } = await tool('vite', site.root);
|
|
161
161
|
const entry = path.join(site.generated, 'theme-bootstrap.mjs');
|
|
@@ -210,11 +210,11 @@ async function portableThemeStyles(site) {
|
|
|
210
210
|
return styles;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
/** Build through
|
|
213
|
+
/** Build through MarkupKit, then make opaque preview scripts portable to static hosts without CORS. */
|
|
214
214
|
export async function buildDocumentation({ root = process.cwd(), config = {}, catalog } = {}) {
|
|
215
215
|
return withBuildLock(root, async () => {
|
|
216
216
|
const site = await prepareDocumentation({ root, config, catalog });
|
|
217
|
-
const { buildApplication } = await tool('@
|
|
217
|
+
const { buildApplication } = await tool('@threadlabs/markupkit', site.root);
|
|
218
218
|
const built = await buildApplication(await documentationOptions(site));
|
|
219
219
|
return { ...built, site };
|
|
220
220
|
});
|
package/editor/expressmark.js
CHANGED
|
@@ -109,7 +109,7 @@ function safeBackground(value, path) {
|
|
|
109
109
|
value: "color",
|
|
110
110
|
attributes: { style }
|
|
111
111
|
}]
|
|
112
|
-
})), (node) => typeof node.attributes?.style === "string")?.attributes?.style;
|
|
112
|
+
}), { syntax: "compatible" }), (node) => typeof node.attributes?.style === "string")?.attributes?.style;
|
|
113
113
|
if (typeof accepted !== "string" || accepted.replace(/\s/g, "").replace(/;$/, "") !== style.replace(/\s/g, "")) fail(path, "unsafe or unsupported table background");
|
|
114
114
|
}
|
|
115
115
|
function safeNavigation(value, image, path) {
|
|
@@ -129,7 +129,7 @@ function safeNavigation(value, image, path) {
|
|
|
129
129
|
value: "link"
|
|
130
130
|
}]
|
|
131
131
|
}]
|
|
132
|
-
})), (child) => child.type === (image ? "image" : "link"))?.url !== value) fail(path, "unsafe or unsupported navigation URL");
|
|
132
|
+
}), { syntax: "compatible" }), (child) => child.type === (image ? "image" : "link"))?.url !== value) fail(path, "unsafe or unsupported navigation URL");
|
|
133
133
|
}
|
|
134
134
|
var MARKS = {
|
|
135
135
|
bold: "strong",
|
|
@@ -605,6 +605,7 @@ function editorDocumentToExpressmark(document, options = {}) {
|
|
|
605
605
|
return {
|
|
606
606
|
type: "document",
|
|
607
607
|
version: 1,
|
|
608
|
+
syntax: options.syntax ?? "compatible",
|
|
608
609
|
body: (document.content ?? []).map((node, index) => {
|
|
609
610
|
const child = toNode(node, `document.body[${index}]`, context);
|
|
610
611
|
return child.type === "image" ? {
|
|
@@ -1007,7 +1008,11 @@ function expressmarkToEditorDocument(document) {
|
|
|
1007
1008
|
* @failure Unsupported editor data raises EditorMarkdownConversionError before any input is changed.
|
|
1008
1009
|
*/
|
|
1009
1010
|
function editorDocumentToMarkdown(document, options = {}) {
|
|
1010
|
-
|
|
1011
|
+
const conversion = {
|
|
1012
|
+
syntax: "compatible",
|
|
1013
|
+
...options
|
|
1014
|
+
};
|
|
1015
|
+
return stringify(editorDocumentToExpressmark(document, conversion), conversion);
|
|
1011
1016
|
}
|
|
1012
1017
|
/**
|
|
1013
1018
|
* Serializes the current editor, including its current display cache and concrete TOC entries.
|
|
@@ -1024,7 +1029,10 @@ function editorToMarkdown(editor, options = {}) {
|
|
|
1024
1029
|
* @failure Unsupported content or root metadata stops conversion instead of being silently flattened.
|
|
1025
1030
|
*/
|
|
1026
1031
|
function markdownToEditorDocument(markdown, options = {}) {
|
|
1027
|
-
return expressmarkToEditorDocument(parse(markdown,
|
|
1032
|
+
return expressmarkToEditorDocument(parse(markdown, {
|
|
1033
|
+
syntax: "compatible",
|
|
1034
|
+
...options
|
|
1035
|
+
}));
|
|
1028
1036
|
}
|
|
1029
1037
|
//#endregion
|
|
1030
1038
|
export { EditorMarkdownConversionError, editorDocumentToExpressmark, editorDocumentToMarkdown, editorToMarkdown, expressmarkToEditorDocument, markdownToEditorDocument };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threadlabs/looma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"lowlight": "^3.3.0",
|
|
120
120
|
"markdown-it": "14.3.1",
|
|
121
121
|
"lucide": "~0.554.0",
|
|
122
|
-
"expressmark": "0.1
|
|
122
|
+
"expressmark": ">=0.2.0 <1"
|
|
123
123
|
},
|
|
124
124
|
"peerDependencies": {
|
|
125
125
|
"@nextwebwg/html-next": "1.0.0-alpha.69",
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"@tiptap/pm": ">=2 <3",
|
|
128
128
|
"@tiptap/vue-3": ">=2 <3",
|
|
129
129
|
"vue": "^3.5.43",
|
|
130
|
-
"markupress": "
|
|
131
|
-
"@
|
|
132
|
-
"vite": "
|
|
130
|
+
"markupress": ">=0.10.0 <1",
|
|
131
|
+
"@threadlabs/markupkit": ">=0.2.0 <1",
|
|
132
|
+
"vite": ">=7.2.7 <9"
|
|
133
133
|
},
|
|
134
134
|
"peerDependenciesMeta": {
|
|
135
135
|
"@tiptap/core": {
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"markupress": {
|
|
148
148
|
"optional": true
|
|
149
149
|
},
|
|
150
|
-
"@
|
|
150
|
+
"@threadlabs/markupkit": {
|
|
151
151
|
"optional": true
|
|
152
152
|
},
|
|
153
153
|
"vite": {
|
package/styles/ui-skeleton.css
CHANGED
|
@@ -16,8 +16,20 @@
|
|
|
16
16
|
syntax: "*";
|
|
17
17
|
inherits: false;
|
|
18
18
|
}
|
|
19
|
+
@property --_ui-skeleton-viewport-x {
|
|
20
|
+
syntax: "<length>";
|
|
21
|
+
inherits: false;
|
|
22
|
+
initial-value: 0px;
|
|
23
|
+
}
|
|
24
|
+
@property --_ui-skeleton-viewport-scale {
|
|
25
|
+
syntax: "<number>";
|
|
26
|
+
inherits: false;
|
|
27
|
+
initial-value: 1;
|
|
28
|
+
}
|
|
19
29
|
|
|
20
30
|
:scope:where([data-component~="ui-skeleton"]) {
|
|
31
|
+
--_ui-skeleton-paint-x: var(--_ui-skeleton-viewport-x);
|
|
32
|
+
--_ui-skeleton-paint-scale: var(--_ui-skeleton-viewport-scale);
|
|
21
33
|
display: block !important;
|
|
22
34
|
position: relative;
|
|
23
35
|
box-sizing: border-box !important;
|
|
@@ -59,23 +71,36 @@
|
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
:scope:where([data-component~="ui-skeleton"])[data-ui-skeleton-state~="animated"]::before {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
background-image: linear-gradient(
|
|
75
|
+
90deg,
|
|
76
|
+
transparent,
|
|
77
|
+
light-dark(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.14)) 50%,
|
|
78
|
+
transparent
|
|
79
|
+
);
|
|
80
|
+
background-size: calc(100vw / var(--_ui-skeleton-paint-scale)) 100%;
|
|
81
|
+
background-position: calc(0vw - var(--_ui-skeleton-paint-x)) 0;
|
|
82
|
+
background-repeat: repeat-x;
|
|
83
|
+
animation: ui-skeleton-shimmer 3s linear infinite;
|
|
84
|
+
}
|
|
85
|
+
@keyframes ui-skeleton-shimmer {
|
|
86
|
+
to {
|
|
87
|
+
background-position: calc(100vw / var(--_ui-skeleton-paint-scale) - var(--_ui-skeleton-paint-x)) 0;
|
|
67
88
|
}
|
|
68
89
|
}
|
|
69
90
|
@media (prefers-reduced-motion: reduce) {
|
|
70
91
|
:scope:where([data-component~="ui-skeleton"])[data-ui-skeleton-state~="animated"]::before {
|
|
71
92
|
animation: none;
|
|
93
|
+
background-image: none;
|
|
72
94
|
}
|
|
73
95
|
}
|
|
74
96
|
@media (forced-colors: active) {
|
|
75
97
|
:scope:where([data-component~="ui-skeleton"])::before {
|
|
76
98
|
background: CanvasText;
|
|
77
99
|
opacity: 0.2;
|
|
100
|
+
}
|
|
101
|
+
:scope:where([data-component~="ui-skeleton"])[data-ui-skeleton-state~="animated"]::before {
|
|
78
102
|
animation: none;
|
|
103
|
+
background-image: none;
|
|
79
104
|
}
|
|
80
105
|
}
|
|
81
106
|
:scope:where([data-component~="ui-skeleton"])[hidden] {
|
package/vanilla/UiSkeleton.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// Generated by HTML Next 1.0.0-alpha.69 for Vanilla DOM. Do not edit.
|
|
2
|
-
import { attachGeneratedController, toText, writeAttribute, formatOf, keywordFormat, hostState, acceptProps, manageProps, generatedInputs, checkBoolean, checkFormat, checkString, defineComponent } from "@nextwebwg/html-next/generated-runtime";
|
|
2
|
+
import { attachGeneratedController, toText, writeAttribute, formatOf, keywordFormat, hostState, acceptProps, manageProps, generatedInputs, checkBoolean, checkFormat, checkString, defineComponent, activateModule } from "@nextwebwg/html-next/generated-runtime";
|
|
3
|
+
import * as controller from "../components/ui-skeleton/ui-skeleton.js";
|
|
3
4
|
import "../styles/ui-skeleton.css";
|
|
4
5
|
|
|
5
|
-
const S = { n: [], t: [], f: import.meta.url, g: "ui-skeleton", b: generatedInputs };
|
|
6
|
-
const D = { g: "ui-skeleton", props: { "animated": { "required":false,"default":
|
|
6
|
+
const S = { n: [], t: [], f: import.meta.url, g: "ui-skeleton", a: (host, I) => C(host, I), b: generatedInputs };
|
|
7
|
+
const D = { g: "ui-skeleton", props: { "animated": { "required":false,"default":true, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "height": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" }, "shape": { "required":false,"values":["text","circle","rectangle"],"default":"text", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat)] }, "width": { "required":false,"default":"", c: checkString, t: "string", j: 0, m: "s" } } };
|
|
8
|
+
const C = (host) => activateModule(controller, host);
|
|
7
9
|
|
|
8
10
|
export function createUiSkeleton(options = {}, html) {
|
|
9
11
|
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
package/vue/UiSkeleton.vue
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
<!-- Generated by HTML Next 1.0.0-alpha.69 for Vue 3.5. Do not edit. -->
|
|
2
2
|
<script setup lang="ts">
|
|
3
|
-
import { computed, watchSyncEffect } from 'vue'
|
|
3
|
+
import { computed, getCurrentInstance, ref, watchSyncEffect } from 'vue'
|
|
4
4
|
import type { PropType } from 'vue'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
checkHydratedRoot,
|
|
7
|
+
createDispatch,
|
|
8
|
+
nativeAttrs,
|
|
9
|
+
useComponentHost,
|
|
10
|
+
useReflectedProp,
|
|
11
|
+
} from './host'
|
|
6
12
|
import {
|
|
7
13
|
BINDING_INPUTS_PROP,
|
|
8
14
|
checkedProp,
|
|
9
15
|
checkPropInput,
|
|
10
16
|
type InputBindings,
|
|
17
|
+
propValidityState,
|
|
11
18
|
READY_INPUT,
|
|
12
19
|
requireInputStatus,
|
|
13
20
|
UNRESOLVED_INPUT,
|
|
@@ -24,8 +31,8 @@ const propValidityContract = {
|
|
|
24
31
|
required: false,
|
|
25
32
|
target: { attribute: 'animated' },
|
|
26
33
|
description:
|
|
27
|
-
'
|
|
28
|
-
default:
|
|
34
|
+
'Moves a subtle highlight from left to right. On by default; pass false to keep it static. Reduced-motion preferences always disable the shimmer.',
|
|
35
|
+
default: true,
|
|
29
36
|
},
|
|
30
37
|
height: {
|
|
31
38
|
type: { kind: 'terminal', name: 'string' },
|
|
@@ -62,13 +69,13 @@ const props = defineProps({
|
|
|
62
69
|
[BINDING_INPUTS_PROP]: { type: null as unknown as PropType<InputBindings> },
|
|
63
70
|
})
|
|
64
71
|
const acceptedProps: Record<string, unknown> = {
|
|
65
|
-
animated:
|
|
72
|
+
animated: true,
|
|
66
73
|
height: '',
|
|
67
74
|
shape: 'text',
|
|
68
75
|
width: '',
|
|
69
76
|
}
|
|
70
77
|
const inputTracking = vuePropInputs(acceptedProps, {
|
|
71
|
-
animated:
|
|
78
|
+
animated: true,
|
|
72
79
|
height: '',
|
|
73
80
|
shape: 'text',
|
|
74
81
|
width: '',
|
|
@@ -124,7 +131,9 @@ watchSyncEffect(() => {
|
|
|
124
131
|
void checkedProps.value
|
|
125
132
|
})
|
|
126
133
|
const reflectedProp = useReflectedProp()
|
|
134
|
+
const hydrationInstance = getCurrentInstance()
|
|
127
135
|
|
|
136
|
+
const root = ref<HTMLElement | null>(null)
|
|
128
137
|
checkHydratedRoot('span', 'ui-skeleton')
|
|
129
138
|
|
|
130
139
|
/** The values the styles' :host() and :state() rules test. */
|
|
@@ -135,6 +144,31 @@ const hostState = computed(() =>
|
|
|
135
144
|
checkedProps.value.animated && 'animated',
|
|
136
145
|
].filter(Boolean).join(' ')
|
|
137
146
|
)
|
|
147
|
+
|
|
148
|
+
const dispatch = createDispatch(root)
|
|
149
|
+
|
|
150
|
+
useComponentHost(() => import('../components/ui-skeleton/ui-skeleton.js'), {
|
|
151
|
+
root,
|
|
152
|
+
module: true,
|
|
153
|
+
dispatch,
|
|
154
|
+
controllerSource: {
|
|
155
|
+
specifier: '../components/ui-skeleton/ui-skeleton.js',
|
|
156
|
+
definition: './components/ui-skeleton/ui-skeleton.html',
|
|
157
|
+
},
|
|
158
|
+
props: checkedProps,
|
|
159
|
+
inputs: propInputs,
|
|
160
|
+
inputTracking,
|
|
161
|
+
propInputs: (name: string) => {
|
|
162
|
+
const incoming = hydrationInstance?.vnode.props
|
|
163
|
+
const kebab = name.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase())
|
|
164
|
+
return incoming !== null && incoming !== undefined
|
|
165
|
+
? (incoming[name] ?? incoming[kebab] ?? null)
|
|
166
|
+
: null
|
|
167
|
+
},
|
|
168
|
+
propNames: ['animated', 'height', 'shape', 'width'],
|
|
169
|
+
propValidity: (name: string) =>
|
|
170
|
+
propValidityState({ contract: propValidityContract, values: { ...props } }, name),
|
|
171
|
+
})
|
|
138
172
|
</script>
|
|
139
173
|
|
|
140
174
|
<template>
|
|
@@ -153,6 +187,7 @@ const hostState = computed(() =>
|
|
|
153
187
|
:data-ui-skeleton-prop-shape="reflectedProp('shape', 'shape', checkedProps.shape, undefined, false)"
|
|
154
188
|
:data-ui-skeleton-prop-width="reflectedProp('width', 'width', checkedProps.width, undefined, false)"
|
|
155
189
|
:data-ui-skeleton-state="hostState || undefined"
|
|
190
|
+
ref="root"
|
|
156
191
|
></span>
|
|
157
192
|
</template>
|
|
158
193
|
|
|
@@ -166,13 +201,26 @@ const hostState = computed(() =>
|
|
|
166
201
|
syntax: "*";
|
|
167
202
|
inherits: false;
|
|
168
203
|
}
|
|
169
|
-
@
|
|
170
|
-
|
|
171
|
-
|
|
204
|
+
@property --_ui-skeleton-viewport-x {
|
|
205
|
+
syntax: "<length>";
|
|
206
|
+
inherits: false;
|
|
207
|
+
initial-value: 0px;
|
|
208
|
+
}
|
|
209
|
+
@property --_ui-skeleton-viewport-scale {
|
|
210
|
+
syntax: "<number>";
|
|
211
|
+
inherits: false;
|
|
212
|
+
initial-value: 1;
|
|
213
|
+
}
|
|
214
|
+
@keyframes ui-skeleton-shimmer {
|
|
215
|
+
to {
|
|
216
|
+
background-position: calc(100vw / var(--_ui-skeleton-paint-scale) - var(--_ui-skeleton-paint-x))
|
|
217
|
+
0;
|
|
172
218
|
}
|
|
173
219
|
}
|
|
174
220
|
@scope (.ui-skeleton) to ([data-hn]) {
|
|
175
221
|
:global(:scope) {
|
|
222
|
+
--_ui-skeleton-paint-x: var(--_ui-skeleton-viewport-x);
|
|
223
|
+
--_ui-skeleton-paint-scale: var(--_ui-skeleton-viewport-scale);
|
|
176
224
|
display: block !important;
|
|
177
225
|
position: relative;
|
|
178
226
|
box-sizing: border-box !important;
|
|
@@ -214,18 +262,31 @@ const hostState = computed(() =>
|
|
|
214
262
|
}
|
|
215
263
|
|
|
216
264
|
:global(:scope[data-ui-skeleton-state~="animated"]::before) {
|
|
217
|
-
|
|
265
|
+
background-image: linear-gradient(
|
|
266
|
+
90deg,
|
|
267
|
+
transparent,
|
|
268
|
+
light-dark(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0.14)) 50%,
|
|
269
|
+
transparent
|
|
270
|
+
);
|
|
271
|
+
background-size: calc(100vw / var(--_ui-skeleton-paint-scale)) 100%;
|
|
272
|
+
background-position: calc(0vw - var(--_ui-skeleton-paint-x)) 0;
|
|
273
|
+
background-repeat: repeat-x;
|
|
274
|
+
animation: ui-skeleton-shimmer 3s linear infinite;
|
|
218
275
|
}
|
|
219
276
|
@media (prefers-reduced-motion: reduce) {
|
|
220
277
|
:global(:scope[data-ui-skeleton-state~="animated"]::before) {
|
|
221
278
|
animation: none;
|
|
279
|
+
background-image: none;
|
|
222
280
|
}
|
|
223
281
|
}
|
|
224
282
|
@media (forced-colors: active) {
|
|
225
283
|
:global(:scope::before) {
|
|
226
284
|
background: CanvasText;
|
|
227
285
|
opacity: 0.2;
|
|
286
|
+
}
|
|
287
|
+
:global(:scope[data-ui-skeleton-state~="animated"]::before) {
|
|
228
288
|
animation: none;
|
|
289
|
+
background-image: none;
|
|
229
290
|
}
|
|
230
291
|
}
|
|
231
292
|
:global(:scope[hidden]) {
|
package/vue/chunks/UiSkeleton.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as useReflectedProp, _ as nativeAttrs, a as checkHydratedRoot, t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
2
|
-
import { h as vuePropInputs, i as checkPropInput, m as vPropValidity, t as BINDING_INPUTS_PROP } from "./props.js";
|
|
3
|
-
import { computed, createElementBlock, defineComponent, mergeProps, openBlock, unref, watchSyncEffect, withDirectives } from "vue";
|
|
1
|
+
import { C as useReflectedProp, S as useComponentHost, _ as nativeAttrs, a as checkHydratedRoot, s as createDispatch, t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
2
|
+
import { d as propValidityState, h as vuePropInputs, i as checkPropInput, m as vPropValidity, t as BINDING_INPUTS_PROP } from "./props.js";
|
|
3
|
+
import { computed, createElementBlock, defineComponent, getCurrentInstance, mergeProps, openBlock, ref, unref, watchSyncEffect, withDirectives } from "vue";
|
|
4
4
|
//#region .build/vue/UiSkeleton.vue?vue&type=script&setup=true&lang.ts
|
|
5
5
|
var _hoisted_1 = [
|
|
6
6
|
"data-ui-skeleton-prop-animated",
|
|
@@ -30,8 +30,8 @@ var UiSkeleton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
|
|
|
30
30
|
},
|
|
31
31
|
required: false,
|
|
32
32
|
target: { attribute: "animated" },
|
|
33
|
-
description: "
|
|
34
|
-
default:
|
|
33
|
+
description: "Moves a subtle highlight from left to right. On by default; pass false to keep it static. Reduced-motion preferences always disable the shimmer.",
|
|
34
|
+
default: true
|
|
35
35
|
},
|
|
36
36
|
height: {
|
|
37
37
|
type: {
|
|
@@ -71,12 +71,12 @@ var UiSkeleton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
|
|
|
71
71
|
} };
|
|
72
72
|
const props = __props;
|
|
73
73
|
const inputTracking = vuePropInputs({
|
|
74
|
-
animated:
|
|
74
|
+
animated: true,
|
|
75
75
|
height: "",
|
|
76
76
|
shape: "text",
|
|
77
77
|
width: ""
|
|
78
78
|
}, {
|
|
79
|
-
animated:
|
|
79
|
+
animated: true,
|
|
80
80
|
height: "",
|
|
81
81
|
shape: "text",
|
|
82
82
|
width: ""
|
|
@@ -118,6 +118,8 @@ var UiSkeleton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
|
|
|
118
118
|
checkedProps.value;
|
|
119
119
|
});
|
|
120
120
|
const reflectedProp = useReflectedProp();
|
|
121
|
+
const hydrationInstance = getCurrentInstance();
|
|
122
|
+
const root = ref(null);
|
|
121
123
|
checkHydratedRoot("span", "ui-skeleton");
|
|
122
124
|
/** The values the styles' :host() and :state() rules test. */
|
|
123
125
|
const hostState = computed(() => [
|
|
@@ -125,6 +127,34 @@ var UiSkeleton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
|
|
|
125
127
|
checkedProps.value.shape != null && `shape=${encodeURIComponent(checkedProps.value.shape)}`,
|
|
126
128
|
checkedProps.value.animated && "animated"
|
|
127
129
|
].filter(Boolean).join(" "));
|
|
130
|
+
const dispatch = createDispatch(root);
|
|
131
|
+
useComponentHost(() => import("@threadlabs/looma/components/ui-skeleton/ui-skeleton.js"), {
|
|
132
|
+
root,
|
|
133
|
+
module: true,
|
|
134
|
+
dispatch,
|
|
135
|
+
controllerSource: {
|
|
136
|
+
specifier: "../components/ui-skeleton/ui-skeleton.js",
|
|
137
|
+
definition: "./components/ui-skeleton/ui-skeleton.html"
|
|
138
|
+
},
|
|
139
|
+
props: checkedProps,
|
|
140
|
+
inputs: propInputs,
|
|
141
|
+
inputTracking,
|
|
142
|
+
propInputs: (name) => {
|
|
143
|
+
const incoming = hydrationInstance?.vnode.props;
|
|
144
|
+
const kebab = name.replace(/[A-Z]/g, (letter) => "-" + letter.toLowerCase());
|
|
145
|
+
return incoming !== null && incoming !== void 0 ? incoming[name] ?? incoming[kebab] ?? null : null;
|
|
146
|
+
},
|
|
147
|
+
propNames: [
|
|
148
|
+
"animated",
|
|
149
|
+
"height",
|
|
150
|
+
"shape",
|
|
151
|
+
"width"
|
|
152
|
+
],
|
|
153
|
+
propValidity: (name) => propValidityState({
|
|
154
|
+
contract: propValidityContract,
|
|
155
|
+
values: { ...props }
|
|
156
|
+
}, name)
|
|
157
|
+
});
|
|
128
158
|
return (_ctx, _cache) => {
|
|
129
159
|
return withDirectives((openBlock(), createElementBlock("span", mergeProps({
|
|
130
160
|
class: "ui-skeleton",
|
|
@@ -139,13 +169,15 @@ var UiSkeleton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__P
|
|
|
139
169
|
"data-ui-skeleton-prop-height": unref(reflectedProp)("height", "height", checkedProps.value.height, void 0, false),
|
|
140
170
|
"data-ui-skeleton-prop-shape": unref(reflectedProp)("shape", "shape", checkedProps.value.shape, void 0, false),
|
|
141
171
|
"data-ui-skeleton-prop-width": unref(reflectedProp)("width", "width", checkedProps.value.width, void 0, false),
|
|
142
|
-
"data-ui-skeleton-state": hostState.value || void 0
|
|
172
|
+
"data-ui-skeleton-state": hostState.value || void 0,
|
|
173
|
+
ref_key: "root",
|
|
174
|
+
ref: root
|
|
143
175
|
}), null, 16, _hoisted_1)), [[unref(vPropValidity), {
|
|
144
176
|
contract: propValidityContract,
|
|
145
177
|
values: { ...props }
|
|
146
178
|
}]]);
|
|
147
179
|
};
|
|
148
180
|
}
|
|
149
|
-
}), [["__scopeId", "data-v-
|
|
181
|
+
}), [["__scopeId", "data-v-908ae327"]]);
|
|
150
182
|
//#endregion
|
|
151
183
|
export { UiSkeleton_default as t };
|