@jxsuite/studio 0.27.0 → 0.28.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/dist/studio.js +33900 -56705
- package/dist/studio.js.map +128 -396
- package/package.json +4 -10
- package/src/browse/browse.ts +62 -22
- package/src/canvas/canvas-live-render.ts +57 -55
- package/src/canvas/canvas-render.ts +50 -21
- package/src/editor/context-menu.ts +4 -1
- package/src/editor/convert-to-component.ts +8 -2
- package/src/editor/inline-edit.ts +7 -2
- package/src/editor/insertion-helper.ts +12 -3
- package/src/editor/slash-menu.ts +5 -1
- package/src/files/file-ops.ts +121 -102
- package/src/files/files.ts +53 -35
- package/src/format/constraints.ts +55 -0
- package/src/format/format-host.ts +212 -0
- package/src/new-project/new-project-modal.ts +18 -3
- package/src/panels/ai-panel.ts +3 -1
- package/src/panels/block-action-bar.ts +4 -2
- package/src/panels/canvas-dnd.ts +37 -8
- package/src/panels/data-explorer.ts +9 -2
- package/src/panels/editors.ts +1 -1
- package/src/panels/git-panel.ts +18 -8
- package/src/panels/head-panel.ts +12 -5
- package/src/panels/left-panel.ts +7 -4
- package/src/panels/panel-events.ts +3 -1
- package/src/panels/properties-panel.ts +9 -3
- package/src/panels/quick-search.ts +10 -10
- package/src/panels/right-panel.ts +6 -2
- package/src/panels/shared.ts +6 -1
- package/src/panels/signals-panel.ts +35 -10
- package/src/panels/style-inputs.ts +5 -1
- package/src/panels/style-panel.ts +6 -2
- package/src/panels/stylebook-layers-panel.ts +12 -3
- package/src/panels/stylebook-panel.ts +24 -8
- package/src/panels/toolbar.ts +16 -3
- package/src/platforms/devserver.ts +32 -3
- package/src/resize-edges.ts +12 -2
- package/src/services/cem-export.ts +9 -3
- package/src/settings/content-types-editor.ts +7 -2
- package/src/settings/defs-editor.ts +6 -1
- package/src/settings/general-settings.ts +3 -1
- package/src/settings/schema-field-ui.ts +11 -3
- package/src/settings/settings-modal.ts +4 -1
- package/src/state.ts +5 -1
- package/src/studio.ts +27 -16
- package/src/tabs/tab.ts +29 -6
- package/src/tabs/transact.ts +4 -1
- package/src/types.ts +15 -6
- package/src/ui/button-group.ts +6 -1
- package/src/ui/expression-editor.ts +14 -3
- package/src/ui/layers.ts +5 -1
- package/src/ui/unit-selector.ts +6 -1
- package/src/utils/canvas-media.ts +1 -1
- package/src/utils/google-fonts.ts +4 -1
- package/src/utils/studio-utils.ts +7 -1
- package/src/view.ts +8 -2
- package/src/markdown/md-allowlist.ts +0 -104
- package/src/markdown/md-convert.ts +0 -846
package/src/tabs/tab.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
import { reactive, effectScope } from "../reactivity";
|
|
3
|
+
import { formatByName, formatForPath } from "../format/format-host";
|
|
3
4
|
import type {
|
|
4
5
|
GitDiffState,
|
|
5
6
|
InlineEditDef,
|
|
@@ -47,7 +48,11 @@ export interface Tab {
|
|
|
47
48
|
documentPath: string | null;
|
|
48
49
|
fileHandle: FileSystemFileHandle | null;
|
|
49
50
|
capabilities: { modes: string[] };
|
|
50
|
-
scope: {
|
|
51
|
+
scope: {
|
|
52
|
+
stop(): void;
|
|
53
|
+
run<T>(fn: () => T): T | undefined;
|
|
54
|
+
[k: string]: unknown;
|
|
55
|
+
};
|
|
51
56
|
doc: {
|
|
52
57
|
document: JxMutableNode;
|
|
53
58
|
content: { frontmatter: Record<string, unknown> };
|
|
@@ -152,8 +157,7 @@ export function createTab({
|
|
|
152
157
|
document,
|
|
153
158
|
sourceFormat,
|
|
154
159
|
content: { frontmatter: frontmatter || {} },
|
|
155
|
-
mode:
|
|
156
|
-
sourceFormat === "md" ? "content" : documentPath?.endsWith(".md") ? "content" : "component",
|
|
160
|
+
mode: inferDocumentMode(documentPath, sourceFormat),
|
|
157
161
|
handlersSource: null,
|
|
158
162
|
dirty: false,
|
|
159
163
|
}),
|
|
@@ -163,7 +167,12 @@ export function createTab({
|
|
|
163
167
|
clipboard: null,
|
|
164
168
|
documentStack: [],
|
|
165
169
|
ui: createDefaultUi(),
|
|
166
|
-
canvas: {
|
|
170
|
+
canvas: {
|
|
171
|
+
status: "idle",
|
|
172
|
+
scope: null,
|
|
173
|
+
error: null,
|
|
174
|
+
pendingInlineEdit: null,
|
|
175
|
+
},
|
|
167
176
|
}),
|
|
168
177
|
history: reactive({
|
|
169
178
|
snapshots: [{ document: structuredClone(document), selection: null }],
|
|
@@ -181,11 +190,25 @@ export function createTab({
|
|
|
181
190
|
*/
|
|
182
191
|
function inferModes(documentPath: string | null | undefined, sourceFormat: string | null) {
|
|
183
192
|
if (documentPath === "project.json") return ["stylebook", "source"];
|
|
184
|
-
|
|
185
|
-
|
|
193
|
+
const format = formatByName(sourceFormat) ?? formatForPath(documentPath);
|
|
194
|
+
if (format) return format.studio?.modes ?? ["edit", "design", "preview", "source"];
|
|
186
195
|
return ALL_MODES;
|
|
187
196
|
}
|
|
188
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Document mode for a new tab: format-class documents default to their $studio.documentMode
|
|
200
|
+
* (content unless promoted to component); JSON is component.
|
|
201
|
+
*
|
|
202
|
+
* @param {string | null | undefined} documentPath
|
|
203
|
+
* @param {string | null} sourceFormat
|
|
204
|
+
* @returns {string}
|
|
205
|
+
*/
|
|
206
|
+
function inferDocumentMode(documentPath: string | null | undefined, sourceFormat: string | null) {
|
|
207
|
+
const format = formatByName(sourceFormat) ?? formatForPath(documentPath);
|
|
208
|
+
if (format) return format.studio?.documentMode?.default ?? "content";
|
|
209
|
+
return "component";
|
|
210
|
+
}
|
|
211
|
+
|
|
189
212
|
/**
|
|
190
213
|
* Dispose a tab — stops its effectScope, killing all effects created within it.
|
|
191
214
|
*
|
package/src/tabs/transact.ts
CHANGED
|
@@ -145,7 +145,10 @@ export function mutateWrapNode(tab: Tab, path: JxPath, wrapperTag: string = "div
|
|
|
145
145
|
if (!node) return;
|
|
146
146
|
const elemPath = parentElementPath(path) as JxPath;
|
|
147
147
|
const idx = childIndex(path) as number;
|
|
148
|
-
const wrapper = {
|
|
148
|
+
const wrapper = {
|
|
149
|
+
tagName: wrapperTag,
|
|
150
|
+
children: [structuredClone(toRaw(node))],
|
|
151
|
+
};
|
|
149
152
|
(getNodeAtPath(tab.doc.document, elemPath).children as JxMutableNode[]).splice(idx, 1, wrapper);
|
|
150
153
|
tab.session.selection = [...elemPath, "children", idx];
|
|
151
154
|
}
|
package/src/types.ts
CHANGED
|
@@ -67,7 +67,11 @@ export interface StudioPlatform {
|
|
|
67
67
|
} | null>;
|
|
68
68
|
probeRootProject(): Promise<{
|
|
69
69
|
meta: { root: string; name: string };
|
|
70
|
-
info: {
|
|
70
|
+
info: {
|
|
71
|
+
isSiteProject: boolean;
|
|
72
|
+
projectConfig?: ProjectConfig | null;
|
|
73
|
+
directories?: string[];
|
|
74
|
+
};
|
|
71
75
|
} | null>;
|
|
72
76
|
listDirectory(dir: string): Promise<DirEntry[]>;
|
|
73
77
|
readFile(path: string): Promise<string>;
|
|
@@ -81,11 +85,17 @@ export interface StudioPlatform {
|
|
|
81
85
|
removePackage(name: string): Promise<unknown>;
|
|
82
86
|
listPackages(): Promise<PackageInfo[]>;
|
|
83
87
|
codeService(action: string, payload: unknown): Promise<CodeServiceResult | null>;
|
|
84
|
-
resolveSiteContext(
|
|
85
|
-
|
|
86
|
-
|
|
88
|
+
resolveSiteContext(filePath: string): Promise<{
|
|
89
|
+
sitePath: string | null;
|
|
90
|
+
projectConfig?: ProjectConfig;
|
|
91
|
+
fileRelPath?: string;
|
|
92
|
+
}>;
|
|
87
93
|
locateFile(name: string): Promise<string | null>;
|
|
88
|
-
searchFiles(query: string): Promise<DirEntry[]>;
|
|
94
|
+
searchFiles(query: string, extensions?: string[]): Promise<DirEntry[]>;
|
|
95
|
+
/** List the project's registered format classes (auto-discovered from imports). */
|
|
96
|
+
listFormats?(): Promise<unknown[]>;
|
|
97
|
+
/** Invoke a format capability (parse/serialize) — { format, action, source?, doc?, options? }. */
|
|
98
|
+
formatAction?(payload: Record<string, unknown>): Promise<unknown>;
|
|
89
99
|
fetchPluginSchema(src: string, prototype?: string, base?: string): Promise<unknown>;
|
|
90
100
|
gitStatus(): Promise<GitStatusResult>;
|
|
91
101
|
gitBranches(): Promise<GitBranchesResult>;
|
|
@@ -156,7 +166,6 @@ export interface GitDiffState {
|
|
|
156
166
|
filePath: string;
|
|
157
167
|
originalContent: string;
|
|
158
168
|
currentContent: string;
|
|
159
|
-
isMarkdown: boolean;
|
|
160
169
|
fileStatus: string;
|
|
161
170
|
originalDoc?: unknown;
|
|
162
171
|
currentDoc?: unknown;
|
package/src/ui/button-group.ts
CHANGED
|
@@ -40,7 +40,12 @@ export function renderButtonGroup(
|
|
|
40
40
|
const extraSelected = hasExtra && extra.includes(String(value));
|
|
41
41
|
|
|
42
42
|
return html`
|
|
43
|
-
<div
|
|
43
|
+
<div
|
|
44
|
+
class=${classMap({
|
|
45
|
+
"button-group-combo": true,
|
|
46
|
+
"has-overflow": hasExtra,
|
|
47
|
+
})}
|
|
48
|
+
>
|
|
44
49
|
<sp-action-group size="s" compact>
|
|
45
50
|
${values.map(
|
|
46
51
|
(v: string) => html`
|
|
@@ -31,7 +31,10 @@ const OPERATOR_GROUPS = [
|
|
|
31
31
|
{ label: "Arithmetic", ops: ["+", "-", "*", "/", "%"] },
|
|
32
32
|
{ label: "Comparison", ops: ["===", "!==", "<", "<=", ">", ">="] },
|
|
33
33
|
{ label: "Logical", ops: ["&&", "||"] },
|
|
34
|
-
{
|
|
34
|
+
{
|
|
35
|
+
label: "Array methods",
|
|
36
|
+
ops: ["push", "pop", "shift", "unshift", "splice"],
|
|
37
|
+
},
|
|
35
38
|
{ label: "Aggregate", ops: ["reduce", "map", "filter"] },
|
|
36
39
|
];
|
|
37
40
|
|
|
@@ -304,7 +307,12 @@ function renderLiteralEditor(operand: any, onChange: (newVal: any) => void) {
|
|
|
304
307
|
function renderOperandEditor(
|
|
305
308
|
operand: unknown,
|
|
306
309
|
onChange: (newOperand: unknown) => void,
|
|
307
|
-
opts: {
|
|
310
|
+
opts: {
|
|
311
|
+
stateDefs: string[];
|
|
312
|
+
allowEventRef: boolean;
|
|
313
|
+
depth: number;
|
|
314
|
+
mustBeRef?: boolean;
|
|
315
|
+
},
|
|
308
316
|
): import("lit-html").TemplateResult {
|
|
309
317
|
if (opts.mustBeRef) {
|
|
310
318
|
const refVal = ((operand as Record<string, unknown> | null)?.$ref as string) ?? "";
|
|
@@ -337,7 +345,10 @@ function renderOperandEditor(
|
|
|
337
345
|
(r) => onChange({ $ref: r }),
|
|
338
346
|
opts,
|
|
339
347
|
)
|
|
340
|
-
: renderExpressionEditor(operand, onChange, {
|
|
348
|
+
: renderExpressionEditor(operand, onChange, {
|
|
349
|
+
...opts,
|
|
350
|
+
depth: opts.depth + 1,
|
|
351
|
+
})}
|
|
341
352
|
</div>
|
|
342
353
|
`;
|
|
343
354
|
}
|
package/src/ui/layers.ts
CHANGED
|
@@ -48,7 +48,11 @@ export function showDialog<T>(
|
|
|
48
48
|
export function showConfirmDialog(
|
|
49
49
|
headline: string,
|
|
50
50
|
message: string | import("lit-html").TemplateResult,
|
|
51
|
-
opts: {
|
|
51
|
+
opts: {
|
|
52
|
+
confirmLabel?: string;
|
|
53
|
+
cancelLabel?: string;
|
|
54
|
+
destructive?: boolean;
|
|
55
|
+
} = {},
|
|
52
56
|
) {
|
|
53
57
|
const { confirmLabel = "Confirm", cancelLabel = "Cancel", destructive = false } = opts;
|
|
54
58
|
return showDialog(
|
package/src/ui/unit-selector.ts
CHANGED
|
@@ -66,7 +66,12 @@ export function renderUnitSelector(
|
|
|
66
66
|
|
|
67
67
|
return html`
|
|
68
68
|
<div class="style-input-number-unit">
|
|
69
|
-
<div
|
|
69
|
+
<div
|
|
70
|
+
class=${classMap({
|
|
71
|
+
"input-group": true,
|
|
72
|
+
"is-expression": isExpression,
|
|
73
|
+
})}
|
|
74
|
+
>
|
|
70
75
|
<sp-textfield
|
|
71
76
|
size="s"
|
|
72
77
|
placeholder=${numericPlaceholder}
|
|
@@ -83,7 +83,7 @@ export function applyCanvasStyle(
|
|
|
83
83
|
const mediaName = key.slice(1);
|
|
84
84
|
if (mediaName === "--") continue;
|
|
85
85
|
if (activeBreakpoints.has(mediaName) || featureToggles[mediaName]) {
|
|
86
|
-
for (const [prop, v] of Object.entries(/** @type {Record<string, unknown>} */
|
|
86
|
+
for (const [prop, v] of Object.entries(/** @type {Record<string, unknown>} */ val)) {
|
|
87
87
|
if (typeof v === "string" || typeof v === "number") {
|
|
88
88
|
try {
|
|
89
89
|
if (prop.startsWith("--")) el.style.setProperty(prop, String(v));
|
|
@@ -73,7 +73,10 @@ export function ensureGoogleFontPreconnects(head: JxHeadEntry[]) {
|
|
|
73
73
|
e?.attributes?.href === origin,
|
|
74
74
|
);
|
|
75
75
|
if (!exists) {
|
|
76
|
-
const attrs: Record<string, string | boolean> = {
|
|
76
|
+
const attrs: Record<string, string | boolean> = {
|
|
77
|
+
rel: "preconnect",
|
|
78
|
+
href: origin,
|
|
79
|
+
};
|
|
77
80
|
if (origin === "https://fonts.gstatic.com") attrs.crossorigin = "";
|
|
78
81
|
head.push({ tagName: "link", attributes: attrs });
|
|
79
82
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* These are all side-effect-free functions used by style/properties/events panels.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { formatByName, defaultContentFormat } from "../format/format-host";
|
|
7
8
|
import type { ProjectConfig, ContentTypeDef } from "@jxsuite/schema/types";
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -155,7 +156,12 @@ export function findContentTypeSchema(
|
|
|
155
156
|
return { name, schema: def.schema };
|
|
156
157
|
}
|
|
157
158
|
} else {
|
|
158
|
-
const ext =
|
|
159
|
+
const ext =
|
|
160
|
+
def.format === "json"
|
|
161
|
+
? ".json"
|
|
162
|
+
: (formatByName(def.format)?.extensions[0] ??
|
|
163
|
+
defaultContentFormat()?.extensions[0] ??
|
|
164
|
+
".json");
|
|
159
165
|
if (documentPath.startsWith(src + "/") && documentPath.endsWith(ext)) {
|
|
160
166
|
return { name, schema: def.schema };
|
|
161
167
|
}
|
package/src/view.ts
CHANGED
|
@@ -16,7 +16,9 @@ interface ViewState {
|
|
|
16
16
|
panY: number;
|
|
17
17
|
prevCanvasMode: string | null;
|
|
18
18
|
monacoEditor:
|
|
19
|
-
| (import("monaco-editor").editor.IStandaloneCodeEditor & {
|
|
19
|
+
| (import("monaco-editor").editor.IStandaloneCodeEditor & {
|
|
20
|
+
_ignoreNextChange?: boolean;
|
|
21
|
+
})
|
|
20
22
|
| null;
|
|
21
23
|
functionEditor:
|
|
22
24
|
| (import("monaco-editor").editor.IStandaloneCodeEditor & {
|
|
@@ -42,7 +44,11 @@ interface ViewState {
|
|
|
42
44
|
forcedAttrEl: HTMLElement | null;
|
|
43
45
|
elementsCollapsed: Set<string>;
|
|
44
46
|
elementsFilter: string;
|
|
45
|
-
lastDragInput: {
|
|
47
|
+
lastDragInput: {
|
|
48
|
+
clientX: number;
|
|
49
|
+
clientY: number;
|
|
50
|
+
[k: string]: unknown;
|
|
51
|
+
} | null;
|
|
46
52
|
_currentDropTargetRow: HTMLElement | null;
|
|
47
53
|
layerDragSourceHeight: number;
|
|
48
54
|
savedRange: Range | null;
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Md-allowlist.js — Markdown element allowlist and nesting constraints
|
|
3
|
-
*
|
|
4
|
-
* Defines which HTML elements are "native markdown" — they round-trip to pure markdown syntax.
|
|
5
|
-
* Everything else is a Jx component directive.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/** Block-level elements that map directly to markdown syntax */
|
|
9
|
-
export const MD_BLOCK = new Set([
|
|
10
|
-
"h1",
|
|
11
|
-
"h2",
|
|
12
|
-
"h3",
|
|
13
|
-
"h4",
|
|
14
|
-
"h5",
|
|
15
|
-
"h6",
|
|
16
|
-
"p",
|
|
17
|
-
"blockquote",
|
|
18
|
-
"ul",
|
|
19
|
-
"ol",
|
|
20
|
-
"li",
|
|
21
|
-
"pre",
|
|
22
|
-
"hr",
|
|
23
|
-
"table",
|
|
24
|
-
"thead",
|
|
25
|
-
"tbody",
|
|
26
|
-
"tr",
|
|
27
|
-
"th",
|
|
28
|
-
"td",
|
|
29
|
-
]);
|
|
30
|
-
|
|
31
|
-
/** Inline elements that map directly to markdown syntax */
|
|
32
|
-
export const MD_INLINE = new Set(["em", "strong", "del", "code", "a", "img", "br"]);
|
|
33
|
-
|
|
34
|
-
/** All markdown-native elements */
|
|
35
|
-
export const MD_ALL = new Set([...MD_BLOCK, ...MD_INLINE]);
|
|
36
|
-
|
|
37
|
-
/** Elements that cannot contain children */
|
|
38
|
-
export const MD_VOID = new Set(["hr", "br", "img"]);
|
|
39
|
-
|
|
40
|
-
/** Elements that contain only text, not child elements */
|
|
41
|
-
export const MD_TEXT_ONLY = new Set(["code"]);
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Nesting constraints: which child elements are allowed inside each parent. null = any block/inline
|
|
45
|
-
* allowed (used for content root and directive components).
|
|
46
|
-
*
|
|
47
|
-
* @type {Record<
|
|
48
|
-
* string,
|
|
49
|
-
* { block: boolean; inline: boolean; directive: boolean; only: Set<string> | null }
|
|
50
|
-
* >}
|
|
51
|
-
*/
|
|
52
|
-
export const MD_NESTING: Record<
|
|
53
|
-
string,
|
|
54
|
-
{ block: boolean; inline: boolean; directive: boolean; only: Set<string> | null }
|
|
55
|
-
> = {
|
|
56
|
-
_root: { block: true, inline: false, directive: true, only: null },
|
|
57
|
-
h1: { block: false, inline: true, directive: false, only: null },
|
|
58
|
-
h2: { block: false, inline: true, directive: false, only: null },
|
|
59
|
-
h3: { block: false, inline: true, directive: false, only: null },
|
|
60
|
-
h4: { block: false, inline: true, directive: false, only: null },
|
|
61
|
-
h5: { block: false, inline: true, directive: false, only: null },
|
|
62
|
-
h6: { block: false, inline: true, directive: false, only: null },
|
|
63
|
-
p: { block: false, inline: true, directive: true, only: null },
|
|
64
|
-
blockquote: { block: true, inline: false, directive: true, only: null },
|
|
65
|
-
ul: { block: false, inline: false, directive: false, only: new Set(["li"]) },
|
|
66
|
-
ol: { block: false, inline: false, directive: false, only: new Set(["li"]) },
|
|
67
|
-
li: { block: true, inline: true, directive: true, only: null },
|
|
68
|
-
pre: { block: false, inline: false, directive: false, only: new Set(["code"]) },
|
|
69
|
-
table: { block: false, inline: false, directive: false, only: new Set(["thead", "tbody"]) },
|
|
70
|
-
thead: { block: false, inline: false, directive: false, only: new Set(["tr"]) },
|
|
71
|
-
tbody: { block: false, inline: false, directive: false, only: new Set(["tr"]) },
|
|
72
|
-
tr: { block: false, inline: false, directive: false, only: new Set(["th", "td"]) },
|
|
73
|
-
th: { block: false, inline: true, directive: false, only: null },
|
|
74
|
-
td: { block: false, inline: true, directive: false, only: null },
|
|
75
|
-
em: { block: false, inline: true, directive: false, only: null },
|
|
76
|
-
strong: { block: false, inline: true, directive: false, only: null },
|
|
77
|
-
del: { block: false, inline: true, directive: false, only: null },
|
|
78
|
-
a: { block: false, inline: true, directive: false, only: null },
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Check whether a tag is allowed as a child of the given parent tag in content mode.
|
|
83
|
-
*
|
|
84
|
-
* @param {string} parentTag - Parent element tag (or '_root' for content root)
|
|
85
|
-
* @param {string} childTag - Proposed child element tag
|
|
86
|
-
* @returns {boolean}
|
|
87
|
-
*/
|
|
88
|
-
export function isValidChild(parentTag: string, childTag: string) {
|
|
89
|
-
const rule = MD_NESTING[parentTag];
|
|
90
|
-
if (!rule) return true; // directive components allow anything
|
|
91
|
-
|
|
92
|
-
// If there's a strict allowlist, check it
|
|
93
|
-
if (rule.only) return rule.only.has(childTag);
|
|
94
|
-
|
|
95
|
-
const isBlock = MD_BLOCK.has(childTag);
|
|
96
|
-
const isInline = MD_INLINE.has(childTag);
|
|
97
|
-
const isDirective = !MD_ALL.has(childTag);
|
|
98
|
-
|
|
99
|
-
if (isBlock && rule.block) return true;
|
|
100
|
-
if (isInline && rule.inline) return true;
|
|
101
|
-
if (isDirective && rule.directive) return true;
|
|
102
|
-
|
|
103
|
-
return false;
|
|
104
|
-
}
|