@plitzi/sdk-server 0.32.15 → 0.32.16
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 +10 -0
- package/dist/adapters/jsonAdapters.js +2 -1
- package/dist/core/createServer.js +10 -2
- package/dist/core/http/stages/middlewares.js +3 -2
- package/dist/core/http/stages/pluginAssets.js +3 -2
- package/dist/core/http/stages/static.js +3 -2
- package/dist/core/requestParser.js +1 -1
- package/dist/core/server/{ssrServer.js → pageServer.js} +15 -6
- package/dist/core/services/registry.js +2 -2
- package/dist/helpers/cache/defaults.js +3 -3
- package/dist/index.js +1 -1
- package/dist/modules/mcp/catalogs/cssCatalog/border.js +30 -0
- package/dist/modules/mcp/catalogs/cssCatalog/box.js +31 -0
- package/dist/modules/mcp/catalogs/cssCatalog/helpers.js +185 -0
- package/dist/modules/mcp/catalogs/cssCatalog/index.js +131 -0
- package/dist/modules/mcp/catalogs/cssCatalog/layout.js +98 -0
- package/dist/modules/mcp/catalogs/cssCatalog/visual.js +144 -0
- package/dist/modules/mcp/catalogs/registry.js +1 -1
- package/dist/modules/mcp/helpers/guide.js +23 -13
- package/dist/modules/mcp/resources/core.js +5 -2
- package/dist/modules/mcp/resources/primer.js +2 -1
- package/dist/modules/mcp/resources/register.js +6 -3
- package/dist/modules/mcp/server.js +1 -1
- package/dist/modules/mcp/tools/operations/schema/interactions/upsertInteractionFlow.js +3 -2
- package/dist/modules/mcp/tools/operations/style/shared.js +2 -2
- package/dist/modules/mcp/tools/operations/style/write.js +2 -2
- package/dist/modules/mcp/tools/shared/validator/audit.js +1 -4
- package/dist/modules/mcp/tools/shared/validator/css.js +3 -11
- package/dist/modules/mcp/tools/shared/validator/elements.js +4 -1
- package/dist/modules/mcp/tools/shared/validator/index.js +15 -15
- package/dist/modules/mcp/tools/shared/validator/interactions.js +1 -4
- package/dist/modules/oauth/authorize.js +2 -1
- package/dist/modules/oauth/metadata.js +8 -2
- package/dist/modules/oauth/records.js +1 -1
- package/dist/modules/oauth/token.js +2 -2
- package/dist/modules/ssr/registerExternalPlugins.js +1 -1
- package/dist/plugins/manager.js +1 -1
- package/dist/src/core/createServer.d.ts +9 -1
- package/dist/src/core/server/pageServer.d.ts +10 -0
- package/dist/src/core/services/registry.d.ts +1 -1
- package/dist/src/modules/mcp/catalogs/cssCatalog/border.d.ts +4 -0
- package/dist/src/modules/mcp/catalogs/cssCatalog/box.d.ts +4 -0
- package/dist/src/modules/mcp/catalogs/cssCatalog/helpers.d.ts +34 -0
- package/dist/src/modules/mcp/catalogs/{cssCatalog.d.ts → cssCatalog/index.d.ts} +10 -5
- package/dist/src/modules/mcp/catalogs/cssCatalog/layout.d.ts +9 -0
- package/dist/src/modules/mcp/catalogs/cssCatalog/visual.d.ts +8 -0
- package/dist/src/modules/mcp/helpers/guide.d.ts +2 -2
- package/dist/src/modules/mcp/resources/index.d.ts +1 -1
- package/dist/src/modules/mcp/tests/apply.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/bindings.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/css.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/helpers.d.ts +13 -0
- package/dist/src/modules/mcp/tests/interactions.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/pages.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/reads.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/search.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/styles.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/tools.test.d.ts +1 -0
- package/dist/src/modules/mcp/tests/validation.test.d.ts +1 -0
- package/dist/src/modules/mcp/tools/screenshot.d.ts +1 -1
- package/dist/src/modules/oauth/metadata.d.ts +7 -1
- package/package.json +9 -9
- package/dist/modules/mcp/catalogs/cssCatalog.js +0 -205
- package/dist/src/core/server/ssrServer.d.ts +0 -2
- /package/dist/src/modules/mcp/{mcp.test.d.ts → catalogs/cssCatalog/cssCatalog.test.d.ts} +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { ANIMATION_DIRECTIONS, ANIMATION_FILL_MODES, ANIMATION_PLAY_STATES, FONT_STYLE_KEYWORDS, FONT_VARIANT_KEYWORDS, FONT_WEIGHT_KEYWORDS, LENGTH_RE, LIST_STYLE_POSITIONS, LIST_STYLE_TYPES, NUMBER_RE, TEXT_DECORATION_LINES, TEXT_DECORATION_STYLES, TIME_RE, isTimingFunction, splitOn, splitPair, splitTokens } from "./helpers.js";
|
|
2
|
+
import { classifyBorderTokens } from "./border.js";
|
|
3
|
+
//#region src/modules/mcp/catalogs/cssCatalog/visual.ts
|
|
4
|
+
var expandLayers = (value, out, expandLayer) => {
|
|
5
|
+
const layers = splitOn(value, ",");
|
|
6
|
+
if (layers.length === 1) {
|
|
7
|
+
expandLayer(layers[0], out);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const perLayer = layers.map((layer) => {
|
|
11
|
+
const layerOut = {};
|
|
12
|
+
expandLayer(layer, layerOut);
|
|
13
|
+
return layerOut;
|
|
14
|
+
});
|
|
15
|
+
const keys = new Set(perLayer.flatMap((layer) => Object.keys(layer)));
|
|
16
|
+
for (const key of keys) out[key] = perLayer.map((layer) => String(layer[key] ?? "initial")).join(", ");
|
|
17
|
+
};
|
|
18
|
+
var expandOutline = (value, out) => {
|
|
19
|
+
for (const [kind, token] of Object.entries(classifyBorderTokens(value))) out[`outline-${kind}`] = token;
|
|
20
|
+
};
|
|
21
|
+
var expandListStyle = (value, out) => {
|
|
22
|
+
for (const token of splitTokens(value)) if (token.startsWith("url(")) out["list-style-image"] = token;
|
|
23
|
+
else if (LIST_STYLE_POSITIONS.has(token)) out["list-style-position"] = token;
|
|
24
|
+
else if (LIST_STYLE_TYPES.has(token)) out["list-style-type"] = token;
|
|
25
|
+
};
|
|
26
|
+
var expandTextDecoration = (value, out) => {
|
|
27
|
+
for (const token of splitTokens(value)) if (TEXT_DECORATION_LINES.has(token)) out["text-decoration-line"] = token;
|
|
28
|
+
else if (TEXT_DECORATION_STYLES.has(token)) out["text-decoration-style"] = token;
|
|
29
|
+
else out["text-decoration-color"] = token;
|
|
30
|
+
};
|
|
31
|
+
var expandTransitionLayer = (layer, out) => {
|
|
32
|
+
let foundDuration = false;
|
|
33
|
+
for (const token of splitTokens(layer)) if (isTimingFunction(token)) out["transition-timing-function"] = token;
|
|
34
|
+
else if (TIME_RE.test(token) || NUMBER_RE.test(token)) if (foundDuration) out["transition-delay"] = token;
|
|
35
|
+
else {
|
|
36
|
+
out["transition-duration"] = token;
|
|
37
|
+
foundDuration = true;
|
|
38
|
+
}
|
|
39
|
+
else if (!out["transition-property"]) out["transition-property"] = token;
|
|
40
|
+
};
|
|
41
|
+
var expandTransition = (value, out) => expandLayers(value, out, expandTransitionLayer);
|
|
42
|
+
var expandAnimationLayer = (layer, out) => {
|
|
43
|
+
let foundDuration = false;
|
|
44
|
+
for (const token of splitTokens(layer)) if (isTimingFunction(token)) out["animation-timing-function"] = token;
|
|
45
|
+
else if (TIME_RE.test(token)) if (foundDuration) out["animation-delay"] = token;
|
|
46
|
+
else {
|
|
47
|
+
out["animation-duration"] = token;
|
|
48
|
+
foundDuration = true;
|
|
49
|
+
}
|
|
50
|
+
else if (token === "infinite" || NUMBER_RE.test(token)) out["animation-iteration-count"] = token;
|
|
51
|
+
else if (ANIMATION_DIRECTIONS.has(token) && !out["animation-direction"]) out["animation-direction"] = token;
|
|
52
|
+
else if (ANIMATION_FILL_MODES.has(token) && !out["animation-fill-mode"]) out["animation-fill-mode"] = token;
|
|
53
|
+
else if (ANIMATION_PLAY_STATES.has(token) && !out["animation-play-state"]) out["animation-play-state"] = token;
|
|
54
|
+
else if (!out["animation-name"]) out["animation-name"] = token;
|
|
55
|
+
};
|
|
56
|
+
var expandAnimation = (value, out) => expandLayers(value, out, expandAnimationLayer);
|
|
57
|
+
var BACKGROUND_REPEATS = /* @__PURE__ */ new Set([
|
|
58
|
+
"repeat",
|
|
59
|
+
"no-repeat",
|
|
60
|
+
"repeat-x",
|
|
61
|
+
"repeat-y",
|
|
62
|
+
"space",
|
|
63
|
+
"round"
|
|
64
|
+
]);
|
|
65
|
+
var BACKGROUND_ATTACHMENTS = /* @__PURE__ */ new Set([
|
|
66
|
+
"scroll",
|
|
67
|
+
"fixed",
|
|
68
|
+
"local"
|
|
69
|
+
]);
|
|
70
|
+
var BACKGROUND_BOXES = /* @__PURE__ */ new Set([
|
|
71
|
+
"border-box",
|
|
72
|
+
"padding-box",
|
|
73
|
+
"content-box"
|
|
74
|
+
]);
|
|
75
|
+
var BACKGROUND_POSITIONS = /* @__PURE__ */ new Set([
|
|
76
|
+
"center",
|
|
77
|
+
"top",
|
|
78
|
+
"bottom",
|
|
79
|
+
"left",
|
|
80
|
+
"right"
|
|
81
|
+
]);
|
|
82
|
+
var isImage = (token) => token.startsWith("url(") || token.includes("-gradient(");
|
|
83
|
+
var isPosition = (token) => BACKGROUND_POSITIONS.has(token) || LENGTH_RE.test(token);
|
|
84
|
+
var isSize = (token) => token === "cover" || token === "contain" || token === "auto" || LENGTH_RE.test(token);
|
|
85
|
+
var expandBackgroundLayer = (layer, out) => {
|
|
86
|
+
const [beforeSlash, afterSlash] = splitPair(layer, "/");
|
|
87
|
+
const tokens = splitTokens(beforeSlash);
|
|
88
|
+
if (afterSlash !== void 0) {
|
|
89
|
+
let positionStart = tokens.length;
|
|
90
|
+
while (positionStart > 0 && isPosition(tokens[positionStart - 1])) positionStart -= 1;
|
|
91
|
+
const position = tokens.splice(positionStart, tokens.length - positionStart);
|
|
92
|
+
if (position.length > 0) out["background-position"] = position.join(" ");
|
|
93
|
+
const afterTokens = splitTokens(afterSlash);
|
|
94
|
+
let sizeEnd = 0;
|
|
95
|
+
while (sizeEnd < afterTokens.length && isSize(afterTokens[sizeEnd])) sizeEnd += 1;
|
|
96
|
+
if (sizeEnd > 0) out["background-size"] = afterTokens.slice(0, sizeEnd).join(" ");
|
|
97
|
+
tokens.push(...afterTokens.slice(sizeEnd));
|
|
98
|
+
}
|
|
99
|
+
const positions = [];
|
|
100
|
+
for (const token of tokens) if (isImage(token)) out["background-image"] = token;
|
|
101
|
+
else if (BACKGROUND_REPEATS.has(token)) out["background-repeat"] = token;
|
|
102
|
+
else if (token === "cover" || token === "contain") out["background-size"] = token;
|
|
103
|
+
else if (BACKGROUND_ATTACHMENTS.has(token)) out["background-attachment"] = token;
|
|
104
|
+
else if (BACKGROUND_BOXES.has(token)) if (out["background-origin"]) out["background-clip"] = token;
|
|
105
|
+
else out["background-origin"] = token;
|
|
106
|
+
else if (isPosition(token)) positions.push(token);
|
|
107
|
+
else if (!out["background-color"]) out["background-color"] = token;
|
|
108
|
+
if (positions.length > 0) out["background-position"] = positions.join(" ");
|
|
109
|
+
};
|
|
110
|
+
var expandBackground = (value, out) => expandLayers(value, out, expandBackgroundLayer);
|
|
111
|
+
var expandFont = (value, out) => {
|
|
112
|
+
const [beforeSlash, afterSlash] = splitPair(value, "/");
|
|
113
|
+
const tokens = splitTokens(beforeSlash);
|
|
114
|
+
if (afterSlash !== void 0) {
|
|
115
|
+
const [lineHeight, ...family] = splitTokens(afterSlash);
|
|
116
|
+
out["line-height"] = lineHeight;
|
|
117
|
+
if (family.length > 0) out["font-family"] = family.join(" ");
|
|
118
|
+
}
|
|
119
|
+
const family = [];
|
|
120
|
+
let foundSize = false;
|
|
121
|
+
for (const token of tokens) {
|
|
122
|
+
if (foundSize) {
|
|
123
|
+
family.push(token);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (token === "normal") {
|
|
127
|
+
const slot = [
|
|
128
|
+
"font-style",
|
|
129
|
+
"font-variant",
|
|
130
|
+
"font-weight"
|
|
131
|
+
].find((prop) => !out[prop]);
|
|
132
|
+
if (slot) out[slot] = token;
|
|
133
|
+
} else if (FONT_STYLE_KEYWORDS.has(token) && !out["font-style"]) out["font-style"] = token;
|
|
134
|
+
else if (FONT_VARIANT_KEYWORDS.has(token) && !out["font-variant"]) out["font-variant"] = token;
|
|
135
|
+
else if (FONT_WEIGHT_KEYWORDS.has(token) && !out["font-weight"]) out["font-weight"] = token;
|
|
136
|
+
else if (LENGTH_RE.test(token)) {
|
|
137
|
+
out["font-size"] = token;
|
|
138
|
+
foundSize = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (family.length > 0) out["font-family"] = family.join(" ");
|
|
142
|
+
};
|
|
143
|
+
//#endregion
|
|
144
|
+
export { expandAnimation, expandBackground, expandFont, expandListStyle, expandOutline, expandTextDecoration, expandTransition };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BUILTIN_COMPONENTS } from "./builtinComponents.js";
|
|
2
|
-
import { cssProperties } from "./cssCatalog.js";
|
|
2
|
+
import { cssProperties } from "./cssCatalog/index.js";
|
|
3
3
|
//#region src/modules/mcp/catalogs/registry.ts
|
|
4
4
|
var enrichType = (typeName, info, catalog) => {
|
|
5
5
|
const entry = catalog?.[typeName];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/modules/mcp/helpers/guide.ts
|
|
2
|
-
var serverInstructions = "Plitzi AI server: read-then-write editing of a Plitzi space. Reads follow a filesystem model — list cheap, read one item in detail on demand; never fetch a whole tree you do not need. Workflow: (1) read plitzi://primer/{env} once — it bundles the guide, types, css-properties and page/definition/variable summaries in a single call; (2) plitzi_search with include:\"detail\" to jump to elements — each hit then carries its uri, stateVersion AND full style/resolvedStyle, so an edit needs no per-element read; open a page skeleton or element only when you need its tree/detail (the skeleton already lists the style classes of each node, and plitzi_read fetches many uris at once); (3) plitzi_apply with dryRun to preview a batch; (4) plitzi_apply to persist, passing expectedResourceVersions to guard against concurrent edits — apply and search both hand back the versions you need for the next edit. Use patchElement / patchDefinition to change only some props / CSS (the upsert variants replace them all). An element read (and search include:\"detail\") inlines the CSS of the definitions it attaches under resolvedStyle, so you rarely need a separate definition read. Refs accept a semantic idRef ([A-Za-z0-9_-] starting with a letter, unique, chosen by you) or the raw id — the idRef is ALSO the runtime wiring key, so a provider source is `<type>_<idRef>.<field>`, visible to the provider’s DESCENDANTS only (bind inside its subtree). CSS is kebab-case
|
|
2
|
+
var serverInstructions = "Plitzi AI server: read-then-write editing of a Plitzi space. Reads follow a filesystem model — list cheap, read one item in detail on demand; never fetch a whole tree you do not need. Workflow: (1) read plitzi://primer/{env} once — it bundles the guide, types, css-properties and page/definition/variable summaries in a single call; (2) plitzi_search with include:\"detail\" to jump to elements — each hit then carries its uri, stateVersion AND full style/resolvedStyle, so an edit needs no per-element read; open a page skeleton or element only when you need its tree/detail (the skeleton already lists the style classes of each node, and plitzi_read fetches many uris at once); (3) plitzi_apply with dryRun to preview a batch; (4) plitzi_apply to persist, passing expectedResourceVersions to guard against concurrent edits — apply and search both hand back the versions you need for the next edit. Use patchElement / patchDefinition to change only some props / CSS (the upsert variants replace them all). An element read (and search include:\"detail\") inlines the CSS of the definitions it attaches under resolvedStyle, so you rarely need a separate definition read. Refs accept a semantic idRef ([A-Za-z0-9_-] starting with a letter, unique, chosen by you) or the raw id — the idRef is ALSO the runtime wiring key, so a provider source is `<type>_<idRef>.<field>`, visible to the provider’s DESCENDANTS only (bind inside its subtree). CSS is plain kebab-case — write shorthands freely (`border: 1px solid red`, `padding: 8px 16px`, `font: bold 16px/1.5 Arial`), they are expanded to longhands for you and STORED that way, so read-back shows the longhands; style vars are var(--name), schema vars are {{name}}. READERS — do not confuse them: MCP *resources* are the browsable catalog (list them, or open one by URI); plitzi_search FINDS refs by label/type/attribute; plitzi_read BATCH-fetches URIs you already hold. Reach for search/read to work; browse resources to discover. Elements also carry applied style variants + visibility (initialState), data bindings and interaction flows: edit them with patchElement (initialState), upsertBinding/patchBinding/deleteBinding, and upsertInteractionFlow/patchInteractionNode/deleteInteraction. An element read shows all three plus availableVariants (which variant each of its classes offers). Separately, to SHOW the user a small self-contained widget (offline, no space or backend) instead of editing the space — a card, hero, pricing table, a visual answer — use plitzi_render; read plitzi://render/guide for it.";
|
|
3
3
|
var guideQuickstart = `# Plitzi AI MCP — quickstart
|
|
4
4
|
This is the condensed guide; read \`plitzi://guide\` for the full reference (every resource, op and example).
|
|
5
5
|
|
|
@@ -19,10 +19,12 @@ interactions target by it. A dot would split that path; an **underscore is fine*
|
|
|
19
19
|
from the idRef (element types have none), so \`list_food_item\` reads unambiguously as type \`list\`, idRef \`food_item\`.
|
|
20
20
|
|
|
21
21
|
**Styling:** CSS keys are **kebab-case** (\`background-color\`); \`var(--token)\` for style vars, \`{{name}}\` for schema
|
|
22
|
-
vars.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
vars. **Write plain CSS** — shorthands (\`border\`, \`padding\`, \`margin\`, \`gap\`, \`overflow\`, \`flex\`, \`background\`,
|
|
23
|
+
\`font\`, \`transition\`, \`animation\`, \`grid\`, \`grid-row\`/\`grid-column\`, \`place-*\`, \`outline\`, \`columns\`,
|
|
24
|
+
\`list-style\`, \`text-decoration\`) are expanded to their longhands for you, so \`border: 1px solid red\` is stored as
|
|
25
|
+
\`border-top-color\`/\`border-top-width\`/\`border-top-style\`/… That is also how you read them back. Flex layout is
|
|
26
|
+
still \`display: flex\` + \`flex-direction\`/\`align-items\`/…, not a \`flex\` value. Mind a type's \`defaultStyle\`
|
|
27
|
+
(\`text\` is \`display: inline\`). Global styles (\`button {…}\`) and id styles (\`#id\`) have their own ops.
|
|
26
28
|
|
|
27
29
|
**Data bindings** (\`upsertBinding\`, category attributes|style|initialState): connect a \`source\` to a \`to\` field.
|
|
28
30
|
A source \`<type>_<idRef>\` is scoped to the provider's **DESCENDANTS only** — bind inside the provider's subtree
|
|
@@ -202,14 +204,22 @@ pointed at the old name is repointed with it, so the element stays wired. You do
|
|
|
202
204
|
- A definition lives in the **style schema**; an element's \`style.base\` (element schema) is the link that applies
|
|
203
205
|
it. Styling an element = upsertDefinition + upsertElement with that ref in \`style.base\`, in one batch.
|
|
204
206
|
- CSS keys are **kebab-case** (\`background-color\`). camelCase is rejected — read \`plitzi://css-properties\`.
|
|
205
|
-
-
|
|
206
|
-
\`padding\`, \`margin\`, \`inset\`, \`gap\`
|
|
207
|
-
-
|
|
208
|
-
|
|
209
|
-
\`
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
\`
|
|
207
|
+
- **Write normal CSS — shorthands are accepted and expanded for you.** \`border\`, \`border-{side}\`,
|
|
208
|
+
\`border-width\`/\`-color\`/\`-style\`, \`border-radius\`, \`padding\`, \`margin\`, \`inset\`, \`gap\`, \`overflow\`,
|
|
209
|
+
\`flex\`, \`flex-flow\`, \`background\`, \`font\`, \`transition\`, \`animation\`, \`grid\`, \`grid-template\`,
|
|
210
|
+
\`grid-area\`, \`grid-row\`, \`grid-column\`, \`place-content\`, \`place-items\`, \`place-self\`, \`outline\`,
|
|
211
|
+
\`columns\`, \`list-style\`, \`text-decoration\` — the full list is in \`plitzi://css-properties\` under
|
|
212
|
+
\`shorthands\`. They **persist as longhand keys** (that is what a read gives back), so a breakpoint/state/variant
|
|
213
|
+
can still override one property at a time.
|
|
214
|
+
- \`border: 1px solid red\` → \`border-top-width: 1px\`, \`border-top-style: solid\`, \`border-top-color: red\`, …
|
|
215
|
+
for all four sides. A shorthand also RESETS what it omits, so \`border: none\` clears a width a previous
|
|
216
|
+
definition set.
|
|
217
|
+
- Comma-separated layers are kept per longhand: \`transition: opacity 200ms, transform 300ms\` →
|
|
218
|
+
\`transition-property: opacity, transform\` + \`transition-duration: 200ms, 300ms\`.
|
|
219
|
+
- In a **patch**, a shorthand replaces the longhands it controls (\`padding: 8px\` overwrites a previous
|
|
220
|
+
\`padding-left\`), and \`"border": null\` removes all twelve border longhands.
|
|
221
|
+
- **Flex layout is not a \`flex\` value**: set \`display: flex\` **plus** \`flex-direction\`, \`align-items\`,
|
|
222
|
+
\`justify-content\` as separate properties.
|
|
213
223
|
- CSS is grouped by breakpoint: \`desktop\`, \`tablet\`, \`mobile\`.
|
|
214
224
|
- Reference a style variable in CSS as \`var(--name)\`; a schema variable in a prop as \`{{name}}\`.
|
|
215
225
|
- \`element.style.base\` is a **list** of definition refs; other slots go under \`element.style.slots\`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cssProperties } from "../catalogs/cssCatalog.js";
|
|
1
|
+
import { cssProperties, cssShorthands } from "../catalogs/cssCatalog/index.js";
|
|
2
2
|
import { buildTypeRegistry } from "../catalogs/registry.js";
|
|
3
3
|
import "../helpers/uris.js";
|
|
4
4
|
import { guideText } from "../helpers/guide.js";
|
|
@@ -9,7 +9,10 @@ import { envelope } from "./envelope.js";
|
|
|
9
9
|
var readCoreResource = (space, uri) => {
|
|
10
10
|
if (uri === "plitzi://guide") return envelope(guideText);
|
|
11
11
|
if (uri === "plitzi://types") return envelope(buildTypeRegistry(space.schema, space.catalog));
|
|
12
|
-
if (uri === "plitzi://css-properties") return envelope(
|
|
12
|
+
if (uri === "plitzi://css-properties") return envelope({
|
|
13
|
+
properties: cssProperties,
|
|
14
|
+
shorthands: cssShorthands
|
|
15
|
+
});
|
|
13
16
|
};
|
|
14
17
|
//#endregion
|
|
15
18
|
export { readCoreResource };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cssProperties } from "../catalogs/cssCatalog.js";
|
|
1
|
+
import { cssProperties, cssShorthands } from "../catalogs/cssCatalog/index.js";
|
|
2
2
|
import { buildDataSourceCatalog, buildInteractionCatalog } from "../catalogs/observed.js";
|
|
3
3
|
import { buildTypeRegistry } from "../catalogs/registry.js";
|
|
4
4
|
import { guideQuickstart } from "../helpers/guide.js";
|
|
@@ -16,6 +16,7 @@ var readPrimerResource = (space, env, uri) => {
|
|
|
16
16
|
guide: guideQuickstart,
|
|
17
17
|
types: buildTypeRegistry(space.schema, space.catalog),
|
|
18
18
|
cssProperties,
|
|
19
|
+
cssShorthands,
|
|
19
20
|
pages: pageSummariesToAI(space.schema),
|
|
20
21
|
folders: foldersToAI(space.schema),
|
|
21
22
|
definitions: definitionRefs(space.style),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cssProperties } from "../catalogs/cssCatalog.js";
|
|
1
|
+
import { cssProperties, cssShorthands } from "../catalogs/cssCatalog/index.js";
|
|
2
2
|
import { guideText } from "../helpers/guide.js";
|
|
3
3
|
import { resourceErrorMessage } from "./canonical.js";
|
|
4
4
|
import { envelope, jsonContents } from "./envelope.js";
|
|
@@ -36,9 +36,12 @@ var registerResources = (server, getSpace, env, log) => {
|
|
|
36
36
|
text: guideText
|
|
37
37
|
}] })));
|
|
38
38
|
server.registerResource("CSS properties", "plitzi://css-properties", {
|
|
39
|
-
description: "Valid kebab-case CSS property keys",
|
|
39
|
+
description: "Valid kebab-case CSS property keys, plus the shorthands that are accepted and auto-expanded",
|
|
40
40
|
mimeType: "application/json"
|
|
41
|
-
}, () => emitStatic("plitzi://css-properties", () => jsonContents("plitzi://css-properties", envelope(
|
|
41
|
+
}, () => emitStatic("plitzi://css-properties", () => jsonContents("plitzi://css-properties", envelope({
|
|
42
|
+
properties: cssProperties,
|
|
43
|
+
shorthands: cssShorthands
|
|
44
|
+
}))));
|
|
42
45
|
registerRenderResources(server, log);
|
|
43
46
|
const fixed = [
|
|
44
47
|
[
|
|
@@ -43,7 +43,7 @@ var createMcpServer = ({ adapters, getSpaceId, preview, screenshot, logger }) =>
|
|
|
43
43
|
const getSpace = () => spacePromise ??= loadSpace();
|
|
44
44
|
const server = new McpServer({
|
|
45
45
|
name: "plitzi-mcp",
|
|
46
|
-
version: "0.32.
|
|
46
|
+
version: "0.32.16"
|
|
47
47
|
}, { instructions: serverInstructions });
|
|
48
48
|
registerResources(server, getSpace, MCP_ENV, log);
|
|
49
49
|
registerApps(server);
|
|
@@ -16,13 +16,14 @@ var upsertInteractionFlow = (space, env, op) => {
|
|
|
16
16
|
const found = resolveElement(space, env, op.pageRef, op.ref);
|
|
17
17
|
if ("error" in found) return found.error;
|
|
18
18
|
const ownerRef = ensureIdRef(space, found.el);
|
|
19
|
-
const
|
|
19
|
+
const nodes = (op.flowId && !op.nodes[0].id ? [{
|
|
20
20
|
...op.nodes[0],
|
|
21
21
|
id: op.flowId
|
|
22
22
|
}, ...op.nodes.slice(1)] : op.nodes).map((node) => node.elementId === void 0 || node.nodeType === "utility" ? node : {
|
|
23
23
|
...node,
|
|
24
24
|
elementId: resolveTargetRef(space, node.elementId)
|
|
25
|
-
})
|
|
25
|
+
});
|
|
26
|
+
const { flowId, record } = materializeFlow(nodes, ownerRef);
|
|
26
27
|
const interactions = found.el.definition.interactions ?? {};
|
|
27
28
|
const targetFlow = op.flowId ?? flowId;
|
|
28
29
|
let replaced = false;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/modules/mcp/tools/operations/style/shared.ts
|
|
3
|
-
var cssMap = z.record(z.string(), z.union([z.string(), z.number()])).describe("kebab-case CSS
|
|
3
|
+
var cssMap = z.record(z.string(), z.union([z.string(), z.number()])).describe("Plain kebab-case CSS. Shorthands are welcome — `border: 1px solid red`, `padding: 8px 16px`, `font: bold 16px/1.5 Arial`, `transition: opacity 200ms ease` — and are stored as their longhands so a breakpoint/state/variant can override each property on its own. Use var(--name) for style tokens and {{name}} for schema vars.");
|
|
4
4
|
var displayModeCss = z.object({
|
|
5
5
|
desktop: cssMap.optional(),
|
|
6
6
|
tablet: cssMap.optional(),
|
|
@@ -14,7 +14,7 @@ var cssPatchMap = z.record(z.string(), z.union([
|
|
|
14
14
|
z.string(),
|
|
15
15
|
z.number(),
|
|
16
16
|
z.null()
|
|
17
|
-
])).describe("kebab-case CSS
|
|
17
|
+
])).describe("Plain kebab-case CSS merged onto the existing declarations; shorthands are accepted and expanded, so `padding: 8px` replaces all four sides. A value of null removes the property — null on a shorthand (`border: null`) removes every longhand it controls.");
|
|
18
18
|
var displayModeCssPatch = z.object({
|
|
19
19
|
desktop: cssPatchMap.optional(),
|
|
20
20
|
tablet: cssPatchMap.optional(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expandShorthand } from "../../../catalogs/cssCatalog.js";
|
|
1
|
+
import { expandShorthand, expandShorthandPatch } from "../../../catalogs/cssCatalog/index.js";
|
|
2
2
|
import { defUri, defsUri, globalUri, globalsUri, idUri, idsUri, styleVarUri, styleVarsUri } from "../../../helpers/uris.js";
|
|
3
3
|
import { fail } from "../../../helpers/opResult.js";
|
|
4
4
|
import processSelector from "@plitzi/sdk-style/helpers/processSelector";
|
|
@@ -65,7 +65,7 @@ var writeStyleItem = (style, ref, base, slots, itemType, componentType) => {
|
|
|
65
65
|
};
|
|
66
66
|
var mergeCss = (base, patch) => {
|
|
67
67
|
const merged = { ...base };
|
|
68
|
-
for (const [key, value] of Object.entries(patch ?? {})) if (value === null) Reflect.deleteProperty(merged, key);
|
|
68
|
+
for (const [key, value] of Object.entries(expandShorthandPatch(patch ?? {}))) if (value === null) Reflect.deleteProperty(merged, key);
|
|
69
69
|
else merged[key] = value;
|
|
70
70
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
71
71
|
};
|
|
@@ -83,10 +83,7 @@ var collectTouched = (ops) => {
|
|
|
83
83
|
touched.globalStyles.add(op.componentType);
|
|
84
84
|
break;
|
|
85
85
|
case "upsertIdStyle":
|
|
86
|
-
case "patchIdStyle":
|
|
87
|
-
touched.idStyles.add(op.targetId);
|
|
88
|
-
break;
|
|
89
|
-
default: break;
|
|
86
|
+
case "patchIdStyle": touched.idStyles.add(op.targetId);
|
|
90
87
|
}
|
|
91
88
|
return touched;
|
|
92
89
|
};
|
|
@@ -1,20 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { checkStyleVarRefs, checkVarRefs
|
|
1
|
+
import { expandShorthand, isCssProperty, suggestCssProperty } from "../../../catalogs/cssCatalog/index.js";
|
|
2
|
+
import { checkStyleVarRefs, checkVarRefs } from "./context.js";
|
|
3
3
|
//#region src/modules/mcp/tools/shared/validator/css.ts
|
|
4
4
|
var checkCss = (css, path, ctx) => {
|
|
5
5
|
if (!css) return;
|
|
6
6
|
const declared = {};
|
|
7
7
|
for (const [key, value] of Object.entries(css)) if (value !== null) declared[key] = value;
|
|
8
8
|
for (const [key, value] of Object.entries(expandShorthand(declared))) {
|
|
9
|
-
|
|
10
|
-
if (longhands) if (!isCssProperty(key)) ctx.errors.push({
|
|
11
|
-
path: `${path}.${key}`,
|
|
12
|
-
message: `Compound CSS shorthand "${key}" is not supported — write its atomic longhand properties`,
|
|
13
|
-
hint: `Use: ${longhands.join(", ")}. (Note: flex layout is display + flex-direction + flex-grow/shrink/basis, not "flex".)`,
|
|
14
|
-
validValues: longhands
|
|
15
|
-
});
|
|
16
|
-
else warnOnce(ctx, `CSS shorthand "${key}" at ${path}.${key} is accepted but stored as one compound value. Plitzi styling is atomic — prefer the longhands (${longhands.join(", ")}) so a breakpoint/state/variant can override each property independently.`);
|
|
17
|
-
else if (!isCssProperty(key)) {
|
|
9
|
+
if (!isCssProperty(key)) {
|
|
18
10
|
const suggestion = suggestCssProperty(key);
|
|
19
11
|
ctx.errors.push({
|
|
20
12
|
path: `${path}.${key}`,
|
|
@@ -25,7 +25,10 @@ var checkVariantApplication = (initialState, path, ctx) => {
|
|
|
25
25
|
const batch = ctx.batchVariants.get(cls);
|
|
26
26
|
for (const [selector, variant] of Object.entries(selectors)) {
|
|
27
27
|
const names = Array.isArray(variant) ? variant : [variant];
|
|
28
|
-
for (const name of names) if (!((declared?.[selector]?.includes(name) ?? false) || (batch?.has(name) ?? false)))
|
|
28
|
+
for (const name of names) if (!((declared?.[selector]?.includes(name) ?? false) || (batch?.has(name) ?? false))) {
|
|
29
|
+
const avail = declared ? ` (declares: ${Object.entries(declared).map(([s, v]) => `${s}:${v.join("/")}`).join(", ")})` : "";
|
|
30
|
+
warnOnce(ctx, `Element applies variant "${name}" on class "${cls}" (${selector}) at ${path}, but that class defines no such variant${avail}. Create it via upsertDefinition/patchDefinition "variants", or fix the name.`);
|
|
31
|
+
}
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
};
|
|
@@ -191,19 +191,21 @@ var validateOperations = (space, ops) => {
|
|
|
191
191
|
case "patchInteractionNode": {
|
|
192
192
|
checkRef(op.ref, `${base}.ref`, ctx);
|
|
193
193
|
const existing = findElementByRef(space.schema, op.ref)?.definition.interactions?.[op.nodeId];
|
|
194
|
-
if (existing)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
194
|
+
if (existing) {
|
|
195
|
+
const merged = {
|
|
196
|
+
id: existing.id,
|
|
197
|
+
title: op.title ?? existing.title,
|
|
198
|
+
nodeType: existing.type,
|
|
199
|
+
action: op.action ?? existing.action,
|
|
200
|
+
params: {
|
|
201
|
+
...existing.params,
|
|
202
|
+
...op.params ?? {}
|
|
203
|
+
},
|
|
204
|
+
enabled: op.enabled ?? existing.enabled,
|
|
205
|
+
elementId: op.elementId ?? existing.elementId ?? void 0
|
|
206
|
+
};
|
|
207
|
+
checkInteractionNode(merged, base, ctx, op.ref);
|
|
208
|
+
} else checkObservedName(op.action, ctx.observedActions, "Interaction action", "plitzi://interactions", `${base}.action`, ctx);
|
|
207
209
|
break;
|
|
208
210
|
}
|
|
209
211
|
case "deleteInteraction":
|
|
@@ -213,8 +215,6 @@ var validateOperations = (space, ops) => {
|
|
|
213
215
|
message: "Provide exactly one of flowId or nodeId",
|
|
214
216
|
hint: "flowId removes a whole flow; nodeId removes a single step"
|
|
215
217
|
});
|
|
216
|
-
break;
|
|
217
|
-
default: break;
|
|
218
218
|
}
|
|
219
219
|
});
|
|
220
220
|
return {
|
|
@@ -96,10 +96,7 @@ var checkInteractionNode = (node, base, ctx, hostRef) => {
|
|
|
96
96
|
case "callback":
|
|
97
97
|
checkElementCallback(node, base, ctx, hostRef);
|
|
98
98
|
break;
|
|
99
|
-
case "utility":
|
|
100
|
-
checkUtility(node, base, ctx);
|
|
101
|
-
break;
|
|
102
|
-
default: break;
|
|
99
|
+
case "utility": checkUtility(node, base, ctx);
|
|
103
100
|
}
|
|
104
101
|
};
|
|
105
102
|
//#endregion
|
|
@@ -28,7 +28,8 @@ var hiddenFieldsFor = (request, pendingId) => {
|
|
|
28
28
|
return hidden;
|
|
29
29
|
};
|
|
30
30
|
var renderConsent = async (config, res, view) => {
|
|
31
|
-
|
|
31
|
+
const html = await (config.renderConsent ?? renderConsentPage)(view);
|
|
32
|
+
sendHtml(res, 200, html);
|
|
32
33
|
};
|
|
33
34
|
/** Validates the parts of an authorization request that decide WHERE a failure may be reported. Until the client
|
|
34
35
|
* and its redirect target check out, nothing may be sent back to the client. */
|
|
@@ -22,11 +22,17 @@ var resourceMetadataUrl = (config, req) => `${issuerOf(config, req)}${PROTECTED_
|
|
|
22
22
|
*
|
|
23
23
|
* `resource` echoes the path the document was asked for: Claude requires it to match the server URL the user
|
|
24
24
|
* typed, path included, and a dedicated MCP server answers JSON-RPC on every path — so `/.well-known/…/mcp`
|
|
25
|
-
* describes `https://host/mcp` while the bare path describes the origin.
|
|
25
|
+
* describes `https://host/mcp` while the bare path describes the origin.
|
|
26
|
+
*
|
|
27
|
+
* A server mounted at the ORIGIN is `https://host/`, WITH the trailing slash: a host parses the URL the user
|
|
28
|
+
* typed before it does anything with it, and an empty path renders as `/` — that normalized form is what the
|
|
29
|
+
* client sends back as the `resource` parameter (asserted in the connector e2e). A document claiming to be
|
|
30
|
+
* `https://host` then disagrees with the request made against it, and Claude's connector drops the grant it
|
|
31
|
+
* just completed — it takes the token and never opens the session. */
|
|
26
32
|
var protectedResourceMetadata = (config, req) => {
|
|
27
33
|
const issuer = issuerOf(config, req);
|
|
28
34
|
return {
|
|
29
|
-
resource: `${issuer}${canonicalPath(req.path.slice(37))}`,
|
|
35
|
+
resource: `${issuer}${canonicalPath(req.path.slice(37)) || "/"}`,
|
|
30
36
|
authorization_servers: [issuer],
|
|
31
37
|
scopes_supported: scopesOf(config),
|
|
32
38
|
bearer_methods_supported: ["header"]
|
|
@@ -4,8 +4,8 @@ import { randomId, verifyChallenge } from "./pkce.js";
|
|
|
4
4
|
import { dropCode, dropRefresh, getCode, getRefresh, putAccess, putRefresh } from "./records.js";
|
|
5
5
|
import { sendErrorJson, sendJson } from "./respond.js";
|
|
6
6
|
//#region src/modules/oauth/token.ts
|
|
7
|
-
var DEFAULT_REFRESH_TTL_SECONDS =
|
|
8
|
-
var DEFAULT_ACCESS_TTL_SECONDS =
|
|
7
|
+
var DEFAULT_REFRESH_TTL_SECONDS = 2592e3;
|
|
8
|
+
var DEFAULT_ACCESS_TTL_SECONDS = 2592e3;
|
|
9
9
|
var refreshTtlOf = (config) => config.refreshTtlSeconds ?? DEFAULT_REFRESH_TTL_SECONDS;
|
|
10
10
|
var scopeOf = (config, requested) => requested ?? scopesOf(config).join(" ");
|
|
11
11
|
/** The token response, plus a rotated refresh grant when refresh is enabled. Rotation is unconditional: a refresh
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
//#region src/modules/ssr/registerExternalPlugins.ts
|
|
5
|
-
var MANIFEST_TTL_MS =
|
|
5
|
+
var MANIFEST_TTL_MS = 6e5;
|
|
6
6
|
var manifestCache = /* @__PURE__ */ new Map();
|
|
7
7
|
var refreshing = /* @__PURE__ */ new Set();
|
|
8
8
|
var cacheDir;
|
package/dist/plugins/manager.js
CHANGED
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import fs from "node:fs/promises";
|
|
7
7
|
//#region src/plugins/manager.ts
|
|
8
8
|
var META_FILE = "meta.json";
|
|
9
|
-
var DEFAULT_TTL_MS =
|
|
9
|
+
var DEFAULT_TTL_MS = 6048e5;
|
|
10
10
|
var DEFAULT_CACHE_DIR = ".sdk-plugins";
|
|
11
11
|
var PluginManager = class {
|
|
12
12
|
urlPrefix = "/sdk-plugins";
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { SSRServer, SSRServerConfig } from '@plitzi/sdk-shared';
|
|
2
|
-
export { createSSRServer } from './server/
|
|
2
|
+
export { createSSRServer } from './server/pageServer';
|
|
3
3
|
export { createMCPServer } from './server/mcpServer';
|
|
4
4
|
export { resolveServices } from './services/resolve';
|
|
5
5
|
export type { ResolvedServices } from './services/resolve';
|
|
6
|
+
/** The general server: mounts whatever the config asks for — SSR, RSC and MCP together, if that is what it
|
|
7
|
+
* enables — and is what a deployment reaches for when it serves more than one surface from a single port (the
|
|
8
|
+
* package's own standalone harness does exactly that).
|
|
9
|
+
*
|
|
10
|
+
* Prefer the surface-specific factories whenever the surface IS known, so the process states what it serves by
|
|
11
|
+
* the name it calls: createSSRServer for pages + RSC, createMCPServer for a dedicated MCP server. An MCP-only
|
|
12
|
+
* config is handed to the latter here, since the lean pipeline builds none of the render template, caches or
|
|
13
|
+
* plugin manager a page server would carry unused. */
|
|
6
14
|
export declare const createServer: (config: SSRServerConfig) => SSRServer;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ResolvedServices } from '../services/resolve';
|
|
2
|
+
import { SSRServer, SSRServerConfig } from '@plitzi/sdk-shared';
|
|
3
|
+
/** The page-serving machinery: html/rsc caches, the render template and the plugin manager, driving the page
|
|
4
|
+
* pipeline. Which services it mounts is the CALLER's decision — {@link createServer} passes whatever the config
|
|
5
|
+
* enables, createSSRServer pins the page surface — so this unit never second-guesses a factory's promise. */
|
|
6
|
+
export declare const createPageServer: (config: SSRServerConfig, services: ResolvedServices) => SSRServer;
|
|
7
|
+
/** The page server: SSR and RSC, and nothing else. MCP is pinned OFF here even when the config asks for it —
|
|
8
|
+
* what a factory named after a surface mounts must be readable from its name alone. A deployment that wants
|
|
9
|
+
* both surfaces in one process asks {@link createServer} for them; a dedicated MCP server is createMCPServer. */
|
|
10
|
+
export declare const createSSRServer: (config: SSRServerConfig) => SSRServer;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ResolvedServices } from './resolve';
|
|
2
2
|
import { BaseContext, SSRContext, Stage } from '../http/types';
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const buildPagePipeline: (services: ResolvedServices) => Stage<SSRContext>[];
|
|
4
4
|
export declare const buildMCPPipeline: () => Stage<BaseContext>[];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CssProps } from '../../types';
|
|
2
|
+
export declare const classifyBorderTokens: (value: string) => Record<"width" | "style" | "color", string>;
|
|
3
|
+
export declare const expandBorder: (key: string, value: string, out: CssProps) => void;
|
|
4
|
+
export declare const expandBorderGroup: (suffix: string, value: string, out: CssProps) => void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CssProps } from '../../types';
|
|
2
|
+
export declare const expandBox: (key: string, value: string, out: CssProps) => void;
|
|
3
|
+
export declare const expandBorderRadius: (value: string, out: CssProps) => void;
|
|
4
|
+
export declare const expandGap: (value: string, out: CssProps) => void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Split a shorthand value into whitespace-separated tokens, keeping parenthesized and quoted runs whole. */
|
|
2
|
+
export declare const splitTokens: (value: string) => string[];
|
|
3
|
+
/** Split a value on a top-level separator. Used for the comma-separated layers of transition/animation/background
|
|
4
|
+
* and for the `/` of border-radius/grid-template/grid-row. */
|
|
5
|
+
export declare const splitOn: (value: string, separator: "," | "/") => string[];
|
|
6
|
+
/** Split a value on its first top-level `/` — the `a / b` form of border-radius, grid-template, background and
|
|
7
|
+
* font. Returns the half after the slash as undefined when there is none, which is what tells those expanders the
|
|
8
|
+
* second half was not declared at all. */
|
|
9
|
+
export declare const splitPair: (value: string, separator: "/") => [string, string | undefined];
|
|
10
|
+
export declare const TIME_RE: RegExp;
|
|
11
|
+
export declare const NUMBER_RE: RegExp;
|
|
12
|
+
/** A numeric value with an optional unit or `%` — matches both `12px` and `50%`. */
|
|
13
|
+
export declare const LENGTH_RE: RegExp;
|
|
14
|
+
export declare const QUOTE_RE: RegExp;
|
|
15
|
+
/** Resolve the 1–4 value syntax shared by padding/margin/inset (top/right/bottom/left) and border-radius
|
|
16
|
+
* (top-left/top-right/bottom-right/bottom-left): 1 value fills all, 2 pair up, 3 leave the 4th mirroring the 2nd. */
|
|
17
|
+
export declare const expandTo4: (tokens: string[]) => [string, string, string, string];
|
|
18
|
+
export declare const SIDES: readonly ["top", "right", "bottom", "left"];
|
|
19
|
+
export declare const FLEX_DIRECTIONS: Set<string>;
|
|
20
|
+
export declare const FLEX_WRAPS: Set<string>;
|
|
21
|
+
export declare const LIST_STYLE_TYPES: Set<string>;
|
|
22
|
+
export declare const LIST_STYLE_POSITIONS: Set<string>;
|
|
23
|
+
export declare const TEXT_DECORATION_LINES: Set<string>;
|
|
24
|
+
export declare const TEXT_DECORATION_STYLES: Set<string>;
|
|
25
|
+
/** A timing function may also be a function call — cubic-bezier(…) or steps(…). */
|
|
26
|
+
export declare const isTimingFunction: (token: string) => boolean;
|
|
27
|
+
export declare const ANIMATION_DIRECTIONS: Set<string>;
|
|
28
|
+
export declare const ANIMATION_FILL_MODES: Set<string>;
|
|
29
|
+
export declare const ANIMATION_PLAY_STATES: Set<string>;
|
|
30
|
+
export declare const FONT_STYLE_KEYWORDS: Set<string>;
|
|
31
|
+
export declare const FONT_VARIANT_KEYWORDS: Set<string>;
|
|
32
|
+
export declare const FONT_WEIGHT_KEYWORDS: Set<string>;
|
|
33
|
+
export declare const BORDER_STYLES: Set<string>;
|
|
34
|
+
export declare const BORDER_WIDTH_KEYWORDS: Set<string>;
|