@airalogy/aimd-renderer 2.4.1 → 2.6.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/LICENSE +201 -0
- package/README.md +10 -5
- package/README.zh-CN.md +10 -5
- package/dist/__tests__/renderer.test.d.ts +2 -0
- package/dist/__tests__/renderer.test.d.ts.map +1 -0
- package/dist/aimd-renderer.css +1 -1
- package/dist/common/annotateStepReferences.d.ts +10 -0
- package/dist/common/annotateStepReferences.d.ts.map +1 -0
- package/dist/common/assignerHighlighting.d.ts +14 -0
- package/dist/common/assignerHighlighting.d.ts.map +1 -0
- package/dist/common/assignerVisibility.d.ts +33 -0
- package/dist/common/assignerVisibility.d.ts.map +1 -0
- package/dist/common/eventKeys.d.ts +20 -0
- package/dist/common/eventKeys.d.ts.map +1 -0
- package/dist/common/figureNumbering.d.ts +30 -0
- package/dist/common/figureNumbering.d.ts.map +1 -0
- package/dist/common/processor.d.ts +96 -0
- package/dist/common/processor.d.ts.map +1 -0
- package/dist/common/quiz-preview.d.ts +11 -0
- package/dist/common/quiz-preview.d.ts.map +1 -0
- package/dist/common/unified-token-renderer.d.ts +124 -0
- package/dist/common/unified-token-renderer.d.ts.map +1 -0
- package/dist/html/index.d.ts +9 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html.js +1 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +270 -225
- package/dist/locales.d.ts +52 -0
- package/dist/locales.d.ts.map +1 -0
- package/dist/{processor-Cv8E7QsA.js → processor-CHbNEcN8.js} +2977 -2212
- package/dist/vue/index.d.ts +10 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/vue-renderer.d.ts +159 -0
- package/dist/vue/vue-renderer.d.ts.map +1 -0
- package/dist/vue.js +10 -9
- package/package.json +17 -17
- package/src/__tests__/renderer.test.ts +220 -2
- package/src/common/processor.ts +177 -43
- package/src/common/unified-token-renderer.ts +106 -26
- package/src/index.ts +3 -0
- package/src/locales.ts +5 -0
- package/src/styles/katex.css +109 -0
- package/src/vue/index.ts +3 -0
- package/src/vue/vue-renderer.ts +320 -50
package/src/common/processor.ts
CHANGED
|
@@ -512,6 +512,14 @@ import remarkRehype from "remark-rehype"
|
|
|
512
512
|
import { unified } from "unified"
|
|
513
513
|
|
|
514
514
|
import { protectAimdInlineTemplates, remarkAimd } from "@airalogy/aimd-core/parser"
|
|
515
|
+
import {
|
|
516
|
+
formatAimdExampleValue,
|
|
517
|
+
formatAimdExamples,
|
|
518
|
+
getAimdFieldDescription,
|
|
519
|
+
getAimdFieldDisplayLabel,
|
|
520
|
+
getAimdFieldExamples,
|
|
521
|
+
getAimdFieldTitle,
|
|
522
|
+
} from "@airalogy/aimd-core/utils"
|
|
515
523
|
import {
|
|
516
524
|
createAimdRendererMessages,
|
|
517
525
|
getAimdRendererQuizTypeLabel,
|
|
@@ -531,6 +539,7 @@ let mathStylesLoadPromise: Promise<unknown> | null = null
|
|
|
531
539
|
|
|
532
540
|
const EMPTY_EXTRACTED_FIELDS: ExtractedAimdFields = {
|
|
533
541
|
var: [],
|
|
542
|
+
var_definitions: [],
|
|
534
543
|
var_table: [],
|
|
535
544
|
client_assigner: [],
|
|
536
545
|
quiz: [],
|
|
@@ -573,6 +582,7 @@ function createAimdParseInput(content: string) {
|
|
|
573
582
|
function createEmptyExtractedFields(): ExtractedAimdFields {
|
|
574
583
|
return {
|
|
575
584
|
var: [...EMPTY_EXTRACTED_FIELDS.var],
|
|
585
|
+
var_definitions: [...(EMPTY_EXTRACTED_FIELDS.var_definitions || [])],
|
|
576
586
|
var_table: [...EMPTY_EXTRACTED_FIELDS.var_table],
|
|
577
587
|
client_assigner: [...EMPTY_EXTRACTED_FIELDS.client_assigner],
|
|
578
588
|
quiz: [...EMPTY_EXTRACTED_FIELDS.quiz],
|
|
@@ -788,6 +798,121 @@ function buildScaleBandChildren(quizNode: AimdQuizNode): Array<Element | HastTex
|
|
|
788
798
|
} as Element]
|
|
789
799
|
}
|
|
790
800
|
|
|
801
|
+
function createTextNode(value: string): HastText {
|
|
802
|
+
return { type: "text", value }
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
interface FieldMetadataHelp {
|
|
806
|
+
tooltip: string
|
|
807
|
+
description?: string
|
|
808
|
+
examples: string[]
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function getFieldHelpText(definition: { kwargs?: Record<string, unknown> } | undefined): FieldMetadataHelp {
|
|
812
|
+
const description = getAimdFieldDescription(definition)
|
|
813
|
+
const examples = getAimdFieldExamples(definition)
|
|
814
|
+
.map(formatAimdExampleValue)
|
|
815
|
+
.map(example => example.trim())
|
|
816
|
+
.filter(Boolean)
|
|
817
|
+
const exampleText = examples.length > 0 ? `e.g. ${examples.join(", ")}` : undefined
|
|
818
|
+
const tooltipLines = [description, exampleText].filter((value): value is string => Boolean(value))
|
|
819
|
+
|
|
820
|
+
return {
|
|
821
|
+
tooltip: tooltipLines.join("\n"),
|
|
822
|
+
description,
|
|
823
|
+
examples,
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function createFieldMetadataPopover(help: FieldMetadataHelp): Element | null {
|
|
828
|
+
if (!help.description && help.examples.length === 0) {
|
|
829
|
+
return null
|
|
830
|
+
}
|
|
831
|
+
const children: Array<Element | HastText> = []
|
|
832
|
+
if (help.description) {
|
|
833
|
+
children.push({
|
|
834
|
+
type: "element",
|
|
835
|
+
tagName: "span",
|
|
836
|
+
properties: { className: ["aimd-field__metadata-popover-line"] },
|
|
837
|
+
children: [createTextNode(help.description)],
|
|
838
|
+
} as Element)
|
|
839
|
+
}
|
|
840
|
+
if (help.examples.length > 0) {
|
|
841
|
+
children.push({
|
|
842
|
+
type: "element",
|
|
843
|
+
tagName: "span",
|
|
844
|
+
properties: { className: ["aimd-field__metadata-examples"] },
|
|
845
|
+
children: [
|
|
846
|
+
{
|
|
847
|
+
type: "element",
|
|
848
|
+
tagName: "span",
|
|
849
|
+
properties: { className: ["aimd-field__metadata-examples-label"] },
|
|
850
|
+
children: [createTextNode("e.g.")],
|
|
851
|
+
} as Element,
|
|
852
|
+
...help.examples.map((example) => ({
|
|
853
|
+
type: "element",
|
|
854
|
+
tagName: "span",
|
|
855
|
+
properties: { className: ["aimd-field__metadata-example"] },
|
|
856
|
+
children: [createTextNode(example)],
|
|
857
|
+
} as Element)),
|
|
858
|
+
],
|
|
859
|
+
} as Element)
|
|
860
|
+
}
|
|
861
|
+
return {
|
|
862
|
+
type: "element",
|
|
863
|
+
tagName: "span",
|
|
864
|
+
properties: { className: ["aimd-field__metadata-popover"], role: "tooltip" },
|
|
865
|
+
children,
|
|
866
|
+
} as Element
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function createFieldNameElement(id: string, definition: { kwargs?: Record<string, unknown> } | undefined): Element {
|
|
870
|
+
const displayTitle = getAimdFieldDisplayLabel(id, definition)
|
|
871
|
+
const hasCustomTitle = getAimdFieldTitle(definition) !== undefined && displayTitle !== id
|
|
872
|
+
const help = getFieldHelpText(definition)
|
|
873
|
+
const hasHelp = Boolean(help.description) || help.examples.length > 0
|
|
874
|
+
const className = ["aimd-field__name"]
|
|
875
|
+
if (hasCustomTitle || hasHelp) {
|
|
876
|
+
className.push("aimd-field__name--with-metadata")
|
|
877
|
+
}
|
|
878
|
+
if (hasHelp) {
|
|
879
|
+
className.push("aimd-field__metadata-host")
|
|
880
|
+
}
|
|
881
|
+
const children: Array<Element | HastText> = [
|
|
882
|
+
{
|
|
883
|
+
type: "element",
|
|
884
|
+
tagName: "span",
|
|
885
|
+
properties: { className: ["aimd-field__title"] },
|
|
886
|
+
children: [createTextNode(displayTitle)],
|
|
887
|
+
} as Element,
|
|
888
|
+
]
|
|
889
|
+
|
|
890
|
+
if (hasCustomTitle) {
|
|
891
|
+
children.push({
|
|
892
|
+
type: "element",
|
|
893
|
+
tagName: "span",
|
|
894
|
+
properties: { className: ["aimd-field__key"] },
|
|
895
|
+
children: [createTextNode(id)],
|
|
896
|
+
} as Element)
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
const popover = createFieldMetadataPopover(help)
|
|
900
|
+
if (popover) {
|
|
901
|
+
children.push(popover)
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
return {
|
|
905
|
+
type: "element",
|
|
906
|
+
tagName: "span",
|
|
907
|
+
properties: cleanProperties({
|
|
908
|
+
className,
|
|
909
|
+
tabIndex: hasHelp ? 0 : undefined,
|
|
910
|
+
"aria-label": help.tooltip || undefined,
|
|
911
|
+
}),
|
|
912
|
+
children,
|
|
913
|
+
} as Element
|
|
914
|
+
}
|
|
915
|
+
|
|
791
916
|
// ---------------------------------------------------------------------------
|
|
792
917
|
// AIMD handler (remark-rehype custom handler)
|
|
793
918
|
// ---------------------------------------------------------------------------
|
|
@@ -966,23 +1091,18 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
966
1091
|
children: [{ type: "text", value: `[${refs.join(", ")}]` }],
|
|
967
1092
|
} as Element)
|
|
968
1093
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1094
|
+
else if (fieldType === "var") {
|
|
1095
|
+
// Variable: type label + id + optional type annotation
|
|
1096
|
+
const definition = "definition" in node ? node.definition : undefined
|
|
1097
|
+
children.push(
|
|
973
1098
|
{
|
|
974
1099
|
type: "element",
|
|
975
1100
|
tagName: "span",
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
tagName: "span",
|
|
982
|
-
properties: { className: ["aimd-field__name"] },
|
|
983
|
-
children: [{ type: "text", value: id }],
|
|
984
|
-
} as Element,
|
|
985
|
-
)
|
|
1101
|
+
properties: { className: ["aimd-field__scope"] },
|
|
1102
|
+
children: [{ type: "text", value: getAimdRendererScopeLabel("var", messages) }],
|
|
1103
|
+
} as Element,
|
|
1104
|
+
createFieldNameElement(id, definition),
|
|
1105
|
+
)
|
|
986
1106
|
if (definition?.type) {
|
|
987
1107
|
children.push({
|
|
988
1108
|
type: "element",
|
|
@@ -992,11 +1112,13 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
992
1112
|
} as Element)
|
|
993
1113
|
}
|
|
994
1114
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1115
|
+
else if (fieldType === "var_table") {
|
|
1116
|
+
// var_table: render header + table preview
|
|
1117
|
+
const columns = "columns" in node ? (node as any).columns as string[] : []
|
|
1118
|
+
const definition = "definition" in node ? node.definition : undefined
|
|
1119
|
+
const subvarDefs = definition?.subvars
|
|
1120
|
+
children.push(
|
|
1121
|
+
{
|
|
1000
1122
|
type: "element",
|
|
1001
1123
|
tagName: "div",
|
|
1002
1124
|
properties: { className: ["aimd-field__header"] },
|
|
@@ -1004,17 +1126,12 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
1004
1126
|
{
|
|
1005
1127
|
type: "element",
|
|
1006
1128
|
tagName: "span",
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
properties: { className: ["aimd-field__name"] },
|
|
1014
|
-
children: [{ type: "text", value: id }],
|
|
1015
|
-
} as Element,
|
|
1016
|
-
],
|
|
1017
|
-
} as Element,
|
|
1129
|
+
properties: { className: ["aimd-field__scope"] },
|
|
1130
|
+
children: [{ type: "text", value: getAimdRendererScopeLabel("var_table", messages) }],
|
|
1131
|
+
} as Element,
|
|
1132
|
+
createFieldNameElement(id, definition),
|
|
1133
|
+
],
|
|
1134
|
+
} as Element,
|
|
1018
1135
|
)
|
|
1019
1136
|
if (columns && columns.length > 0) {
|
|
1020
1137
|
children.push({
|
|
@@ -1031,12 +1148,14 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
1031
1148
|
type: "element",
|
|
1032
1149
|
tagName: "tr",
|
|
1033
1150
|
properties: {},
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1151
|
+
children: columns.map(col => ({
|
|
1152
|
+
type: "element",
|
|
1153
|
+
tagName: "th",
|
|
1154
|
+
properties: cleanProperties({
|
|
1155
|
+
"data-column-id": col,
|
|
1156
|
+
}),
|
|
1157
|
+
children: [createFieldNameElement(col, subvarDefs?.[col])],
|
|
1158
|
+
} as Element)),
|
|
1040
1159
|
} as Element,
|
|
1041
1160
|
],
|
|
1042
1161
|
} as Element,
|
|
@@ -1171,7 +1290,7 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
1171
1290
|
} as Element)
|
|
1172
1291
|
}
|
|
1173
1292
|
|
|
1174
|
-
if (quizType === "choice" && Array.isArray(quizNode.options) && quizNode.options.length > 0) {
|
|
1293
|
+
if ((quizType === "choice" || quizType === "true_false") && Array.isArray(quizNode.options) && quizNode.options.length > 0) {
|
|
1175
1294
|
children.push({
|
|
1176
1295
|
type: "element",
|
|
1177
1296
|
tagName: "ul",
|
|
@@ -1190,7 +1309,7 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
1190
1309
|
children.push(...buildScaleBandChildren(quizNode))
|
|
1191
1310
|
}
|
|
1192
1311
|
|
|
1193
|
-
if (quizPreview.showAnswers && quizType === "choice" && quizNode.answer !== undefined) {
|
|
1312
|
+
if (quizPreview.showAnswers && (quizType === "choice" || quizType === "true_false") && quizNode.answer !== undefined) {
|
|
1194
1313
|
const answerText = Array.isArray(quizNode.answer)
|
|
1195
1314
|
? quizNode.answer.join(", ")
|
|
1196
1315
|
: String(quizNode.answer)
|
|
@@ -1240,14 +1359,29 @@ function createAimdHandler(options: AimdRendererOptions = {}) {
|
|
|
1240
1359
|
}
|
|
1241
1360
|
|
|
1242
1361
|
// Build properties
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1362
|
+
const properties: Properties = {
|
|
1363
|
+
"className": [baseClass, modifierClass],
|
|
1364
|
+
"data-aimd-type": node.fieldType,
|
|
1246
1365
|
"data-aimd-id": node.id,
|
|
1247
1366
|
"data-aimd-scope": node.scope,
|
|
1248
1367
|
"data-aimd-raw": node.raw,
|
|
1249
|
-
|
|
1250
|
-
|
|
1368
|
+
"data-aimd-json": aimdJson,
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
if ((node.fieldType === "var" || node.fieldType === "var_table") && "definition" in node) {
|
|
1372
|
+
const title = getAimdFieldTitle(node.definition)
|
|
1373
|
+
const description = getAimdFieldDescription(node.definition)
|
|
1374
|
+
const examples = formatAimdExamples(getAimdFieldExamples(node.definition))
|
|
1375
|
+
if (title) {
|
|
1376
|
+
properties["data-aimd-title"] = title
|
|
1377
|
+
}
|
|
1378
|
+
if (description) {
|
|
1379
|
+
properties["data-aimd-description"] = description
|
|
1380
|
+
}
|
|
1381
|
+
if (examples) {
|
|
1382
|
+
properties["data-aimd-examples"] = examples
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1251
1385
|
|
|
1252
1386
|
// Add reference href
|
|
1253
1387
|
if (isRef) {
|
|
@@ -13,6 +13,13 @@ import type {
|
|
|
13
13
|
} from "@airalogy/aimd-core/types"
|
|
14
14
|
import type { AimdNode, QuizPreviewOptions, RenderContext } from "@airalogy/aimd-core/types"
|
|
15
15
|
import type { ExtractedAimdFields } from "@airalogy/aimd-core/types"
|
|
16
|
+
import {
|
|
17
|
+
formatAimdExampleValue,
|
|
18
|
+
getAimdFieldDescription,
|
|
19
|
+
getAimdFieldDisplayLabel,
|
|
20
|
+
getAimdFieldExamples,
|
|
21
|
+
getAimdFieldTitle,
|
|
22
|
+
} from "@airalogy/aimd-core/utils"
|
|
16
23
|
import type { AimdRendererI18nOptions, AimdRendererMessages } from "../locales"
|
|
17
24
|
import type { AimdComponentRenderer, ElementRenderer, ShikiHighlighter, VueRendererOptions } from "../vue/vue-renderer"
|
|
18
25
|
import type { AimdRendererOptions, RenderResult } from "./processor"
|
|
@@ -226,6 +233,74 @@ function buildScaleBandChildren(quizNode: AimdQuizNode): VNode[] {
|
|
|
226
233
|
]
|
|
227
234
|
}
|
|
228
235
|
|
|
236
|
+
interface FieldMetadataHelp {
|
|
237
|
+
tooltip: string
|
|
238
|
+
description?: string
|
|
239
|
+
examples: string[]
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function getFieldHelpText(definition: { kwargs?: Record<string, unknown> } | undefined): FieldMetadataHelp {
|
|
243
|
+
const description = getAimdFieldDescription(definition)
|
|
244
|
+
const examples = getAimdFieldExamples(definition)
|
|
245
|
+
.map(formatAimdExampleValue)
|
|
246
|
+
.map(example => example.trim())
|
|
247
|
+
.filter(Boolean)
|
|
248
|
+
const exampleText = examples.length > 0 ? `e.g. ${examples.join(", ")}` : undefined
|
|
249
|
+
const tooltipLines = [description, exampleText].filter((value): value is string => Boolean(value))
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
tooltip: tooltipLines.join("\n"),
|
|
253
|
+
description,
|
|
254
|
+
examples,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function renderFieldMetadataPopover(help: FieldMetadataHelp): VNode | null {
|
|
259
|
+
if (!help.description && help.examples.length === 0) {
|
|
260
|
+
return null
|
|
261
|
+
}
|
|
262
|
+
const children: VNode[] = []
|
|
263
|
+
if (help.description) {
|
|
264
|
+
children.push(h("span", {
|
|
265
|
+
class: "aimd-field__metadata-popover-line",
|
|
266
|
+
}, help.description))
|
|
267
|
+
}
|
|
268
|
+
if (help.examples.length > 0) {
|
|
269
|
+
children.push(h("span", { class: "aimd-field__metadata-examples" }, [
|
|
270
|
+
h("span", { class: "aimd-field__metadata-examples-label" }, "e.g."),
|
|
271
|
+
...help.examples.map((example, index) => h("span", {
|
|
272
|
+
key: `${index}-${example}`,
|
|
273
|
+
class: "aimd-field__metadata-example",
|
|
274
|
+
}, example)),
|
|
275
|
+
]))
|
|
276
|
+
}
|
|
277
|
+
return h("span", {
|
|
278
|
+
class: "aimd-field__metadata-popover",
|
|
279
|
+
role: "tooltip",
|
|
280
|
+
}, children)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function renderFieldName(id: string, definition: { kwargs?: Record<string, unknown> } | undefined): VNode {
|
|
284
|
+
const displayTitle = getAimdFieldDisplayLabel(id, definition)
|
|
285
|
+
const hasCustomTitle = getAimdFieldTitle(definition) !== undefined && displayTitle !== id
|
|
286
|
+
const help = getFieldHelpText(definition)
|
|
287
|
+
const hasHelp = Boolean(help.description) || help.examples.length > 0
|
|
288
|
+
|
|
289
|
+
return h("span", {
|
|
290
|
+
class: [
|
|
291
|
+
"aimd-field__name",
|
|
292
|
+
(hasCustomTitle || hasHelp) ? "aimd-field__name--with-metadata" : undefined,
|
|
293
|
+
hasHelp ? "aimd-field__metadata-host" : undefined,
|
|
294
|
+
],
|
|
295
|
+
tabindex: hasHelp ? 0 : undefined,
|
|
296
|
+
"aria-label": help.tooltip || undefined,
|
|
297
|
+
}, [
|
|
298
|
+
h("span", { class: "aimd-field__title" }, displayTitle),
|
|
299
|
+
hasCustomTitle ? h("span", { class: "aimd-field__key" }, id) : null,
|
|
300
|
+
renderFieldMetadataPopover(help),
|
|
301
|
+
])
|
|
302
|
+
}
|
|
303
|
+
|
|
229
304
|
/**
|
|
230
305
|
* Render preview tag for AIMD field
|
|
231
306
|
*/
|
|
@@ -234,6 +309,7 @@ function renderPreviewTag(
|
|
|
234
309
|
id: string,
|
|
235
310
|
messages: AimdRendererMessages,
|
|
236
311
|
columns?: string[],
|
|
312
|
+
definition?: { kwargs?: Record<string, unknown>, subvars?: Record<string, { kwargs?: Record<string, unknown> }> },
|
|
237
313
|
): VNode {
|
|
238
314
|
const scopeKey = getScopeKey(scope)
|
|
239
315
|
const scopeLabel = getAimdRendererScopeLabel(scope, messages)
|
|
@@ -241,17 +317,19 @@ function renderPreviewTag(
|
|
|
241
317
|
// var_table: render tag with table preview inside
|
|
242
318
|
if (scope === "var_table") {
|
|
243
319
|
const children: VNode[] = [
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
320
|
+
h("div", { class: "aimd-field__header" }, [
|
|
321
|
+
h("span", { class: "aimd-field__scope" }, messages.scope.table),
|
|
322
|
+
renderFieldName(id, definition),
|
|
323
|
+
]),
|
|
248
324
|
]
|
|
249
325
|
// Add table preview inside the container
|
|
250
326
|
if (columns && columns.length > 0) {
|
|
251
327
|
children.push(
|
|
252
328
|
h("table", { class: "aimd-field__table-preview" }, [
|
|
253
329
|
h("thead", [
|
|
254
|
-
|
|
330
|
+
h("tr", columns.map(col => h("th", {
|
|
331
|
+
"data-column-id": col,
|
|
332
|
+
}, [renderFieldName(col, definition?.subvars?.[col])]))),
|
|
255
333
|
]),
|
|
256
334
|
h("tbody", [
|
|
257
335
|
h("tr", columns.map(() => h("td", "..."))),
|
|
@@ -272,10 +350,10 @@ function renderPreviewTag(
|
|
|
272
350
|
"class": `aimd-field aimd-field--${classSuffix}`,
|
|
273
351
|
"data-aimd-type": scopeKey,
|
|
274
352
|
"data-aimd-id": id,
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
353
|
+
}, [
|
|
354
|
+
h("span", { class: "aimd-field__scope" }, scopeLabel),
|
|
355
|
+
renderFieldName(id, definition),
|
|
356
|
+
])
|
|
279
357
|
}
|
|
280
358
|
|
|
281
359
|
/**
|
|
@@ -299,19 +377,20 @@ function createAimdRenderers(options: UnifiedTokenRendererOptions): Record<strin
|
|
|
299
377
|
resolveQuizPreviewOptions(getMode(), options.quizPreview)
|
|
300
378
|
|
|
301
379
|
return {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
380
|
+
var: async (node, ctx, children) => {
|
|
381
|
+
const varNode = node as AimdVarNode
|
|
382
|
+
const { id, scope } = varNode
|
|
383
|
+
const definition = varNode.definition
|
|
305
384
|
|
|
306
|
-
|
|
385
|
+
if (isPreview()) {
|
|
307
386
|
if (PreviewRenderer) {
|
|
308
387
|
return h(PreviewRenderer, { type: "var" }, {
|
|
309
388
|
default: () => children,
|
|
310
389
|
name: () => id,
|
|
311
390
|
})
|
|
312
391
|
}
|
|
313
|
-
|
|
314
|
-
|
|
392
|
+
return renderPreviewTag(scope, id, messages, undefined, definition)
|
|
393
|
+
}
|
|
315
394
|
|
|
316
395
|
// Edit mode
|
|
317
396
|
if (getTokenProps && AIMDItem) {
|
|
@@ -325,12 +404,13 @@ function createAimdRenderers(options: UnifiedTokenRendererOptions): Record<strin
|
|
|
325
404
|
}
|
|
326
405
|
}
|
|
327
406
|
|
|
328
|
-
|
|
329
|
-
|
|
407
|
+
return renderPreviewTag(scope, id, messages, undefined, definition)
|
|
408
|
+
},
|
|
330
409
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
410
|
+
var_table: async (node, ctx, children) => {
|
|
411
|
+
const tableNode = node as AimdVarTableNode
|
|
412
|
+
const { id, scope, columns } = tableNode
|
|
413
|
+
const definition = tableNode.definition
|
|
334
414
|
|
|
335
415
|
if (isPreview()) {
|
|
336
416
|
if (PreviewRenderer) {
|
|
@@ -340,8 +420,8 @@ function createAimdRenderers(options: UnifiedTokenRendererOptions): Record<strin
|
|
|
340
420
|
})
|
|
341
421
|
}
|
|
342
422
|
// Preview mode: render inline tag with columns info
|
|
343
|
-
|
|
344
|
-
|
|
423
|
+
return renderPreviewTag(scope, id, messages, columns, definition)
|
|
424
|
+
}
|
|
345
425
|
|
|
346
426
|
// Edit mode
|
|
347
427
|
if (getTokenProps && AIMDTag) {
|
|
@@ -349,8 +429,8 @@ function createAimdRenderers(options: UnifiedTokenRendererOptions): Record<strin
|
|
|
349
429
|
return h(AIMDTag, { ...item, props: columns })
|
|
350
430
|
}
|
|
351
431
|
|
|
352
|
-
|
|
353
|
-
|
|
432
|
+
return renderPreviewTag(scope, id, messages, columns, definition)
|
|
433
|
+
},
|
|
354
434
|
|
|
355
435
|
quiz: async (node, ctx, children) => {
|
|
356
436
|
const quizNode = node as AimdQuizNode
|
|
@@ -381,7 +461,7 @@ function createAimdRenderers(options: UnifiedTokenRendererOptions): Record<strin
|
|
|
381
461
|
previewChildren.push(h("div", { class: "aimd-quiz__description" }, quizNode.description))
|
|
382
462
|
}
|
|
383
463
|
|
|
384
|
-
if (quizType === "choice" && Array.isArray(quizNode.options) && quizNode.options.length > 0) {
|
|
464
|
+
if ((quizType === "choice" || quizType === "true_false") && Array.isArray(quizNode.options) && quizNode.options.length > 0) {
|
|
385
465
|
previewChildren.push(
|
|
386
466
|
h("ul", { class: "aimd-quiz__options" }, quizNode.options.map(opt =>
|
|
387
467
|
h("li", `${opt.key}. ${opt.text}`),
|
|
@@ -396,7 +476,7 @@ function createAimdRenderers(options: UnifiedTokenRendererOptions): Record<strin
|
|
|
396
476
|
|
|
397
477
|
const quizPreview = getQuizPreview()
|
|
398
478
|
|
|
399
|
-
if (quizPreview.showAnswers && quizType === "choice" && quizNode.answer !== undefined) {
|
|
479
|
+
if (quizPreview.showAnswers && (quizType === "choice" || quizType === "true_false") && quizNode.answer !== undefined) {
|
|
400
480
|
const answerText = Array.isArray(quizNode.answer)
|
|
401
481
|
? quizNode.answer.join(", ")
|
|
402
482
|
: String(quizNode.answer)
|
package/src/index.ts
CHANGED
|
@@ -51,9 +51,12 @@ export {
|
|
|
51
51
|
createEmbeddedRenderer,
|
|
52
52
|
createMermaidRenderer,
|
|
53
53
|
createStepCardRenderer,
|
|
54
|
+
loadShikiHighlighter,
|
|
55
|
+
type CodeBlockRendererOptions,
|
|
54
56
|
type ElementRenderer,
|
|
55
57
|
hastToVue,
|
|
56
58
|
renderToVNodes,
|
|
59
|
+
type LoadShikiHighlighterOptions,
|
|
57
60
|
type AimdStepCardRendererOptions,
|
|
58
61
|
type ShikiHighlighter,
|
|
59
62
|
type VueRendererOptions,
|
package/src/locales.ts
CHANGED
|
@@ -26,6 +26,7 @@ export interface AimdRendererMessages {
|
|
|
26
26
|
choice: string
|
|
27
27
|
singleChoice: string
|
|
28
28
|
multipleChoice: string
|
|
29
|
+
trueFalse: string
|
|
29
30
|
blank: string
|
|
30
31
|
open: string
|
|
31
32
|
scale: string
|
|
@@ -86,6 +87,7 @@ const EN_US_MESSAGES: AimdRendererMessages = {
|
|
|
86
87
|
choice: "choice",
|
|
87
88
|
singleChoice: "Single choice",
|
|
88
89
|
multipleChoice: "Multiple choice",
|
|
90
|
+
trueFalse: "True/false",
|
|
89
91
|
blank: "blank",
|
|
90
92
|
open: "open",
|
|
91
93
|
scale: "scale",
|
|
@@ -122,6 +124,7 @@ const ZH_CN_MESSAGES: AimdRendererMessages = {
|
|
|
122
124
|
choice: "选择",
|
|
123
125
|
singleChoice: "单选",
|
|
124
126
|
multipleChoice: "多选",
|
|
127
|
+
trueFalse: "判断",
|
|
125
128
|
blank: "填空",
|
|
126
129
|
open: "开放",
|
|
127
130
|
scale: "量表",
|
|
@@ -246,6 +249,8 @@ export function getAimdRendererQuizTypeLabel(
|
|
|
246
249
|
return messages.quiz.types.choice
|
|
247
250
|
case "blank":
|
|
248
251
|
return messages.quiz.types.blank
|
|
252
|
+
case "true_false":
|
|
253
|
+
return messages.quiz.types.trueFalse
|
|
249
254
|
case "open":
|
|
250
255
|
return messages.quiz.types.open
|
|
251
256
|
case "scale":
|
package/src/styles/katex.css
CHANGED
|
@@ -1,2 +1,111 @@
|
|
|
1
1
|
/* Re-export KaTeX base styles for AIMD renderer consumers. */
|
|
2
2
|
@import "katex/dist/katex.min.css";
|
|
3
|
+
|
|
4
|
+
.aimd-field__metadata-host {
|
|
5
|
+
position: relative;
|
|
6
|
+
cursor: help;
|
|
7
|
+
outline: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.aimd-field__metadata-host:hover,
|
|
11
|
+
.aimd-field__metadata-host:focus,
|
|
12
|
+
.aimd-field__metadata-host:focus-within {
|
|
13
|
+
z-index: 90;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.aimd-field__metadata-host:focus-visible {
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
box-shadow: 0 0 0 2px rgba(65, 129, 253, 0.24);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.aimd-field__metadata-host .aimd-field__title {
|
|
22
|
+
text-decoration-line: underline;
|
|
23
|
+
text-decoration-style: dotted;
|
|
24
|
+
text-decoration-color: rgba(15, 23, 42, 0.36);
|
|
25
|
+
text-underline-offset: 3px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.aimd-field__metadata-popover {
|
|
29
|
+
position: absolute;
|
|
30
|
+
z-index: 80;
|
|
31
|
+
inset-inline-start: 0;
|
|
32
|
+
top: calc(100% + 7px);
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: 4px;
|
|
36
|
+
width: max-content;
|
|
37
|
+
min-width: 220px;
|
|
38
|
+
max-width: min(360px, 82vw);
|
|
39
|
+
padding: 8px 10px;
|
|
40
|
+
border-radius: 8px;
|
|
41
|
+
background: rgba(15, 23, 42, 0.96);
|
|
42
|
+
color: #f8fafc;
|
|
43
|
+
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.28);
|
|
44
|
+
font-size: 12px;
|
|
45
|
+
font-weight: 500;
|
|
46
|
+
line-height: 1.45;
|
|
47
|
+
letter-spacing: 0;
|
|
48
|
+
text-align: left;
|
|
49
|
+
text-transform: none;
|
|
50
|
+
white-space: normal;
|
|
51
|
+
pointer-events: none;
|
|
52
|
+
opacity: 0;
|
|
53
|
+
visibility: hidden;
|
|
54
|
+
transform: translateY(-2px);
|
|
55
|
+
transition:
|
|
56
|
+
opacity 120ms ease,
|
|
57
|
+
transform 120ms ease,
|
|
58
|
+
visibility 120ms ease;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.aimd-field__metadata-popover::before {
|
|
62
|
+
content: "";
|
|
63
|
+
position: absolute;
|
|
64
|
+
inset-inline-start: 14px;
|
|
65
|
+
top: -5px;
|
|
66
|
+
width: 10px;
|
|
67
|
+
height: 10px;
|
|
68
|
+
background: rgba(15, 23, 42, 0.96);
|
|
69
|
+
transform: rotate(45deg);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.aimd-field__metadata-popover-line {
|
|
73
|
+
display: block;
|
|
74
|
+
color: inherit;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.aimd-field__metadata-examples {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-wrap: wrap;
|
|
80
|
+
align-items: center;
|
|
81
|
+
gap: 4px;
|
|
82
|
+
padding-top: 1px;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.aimd-field__metadata-examples-label {
|
|
86
|
+
color: rgba(226, 232, 240, 0.78);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.aimd-field__metadata-example {
|
|
90
|
+
display: inline-flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
max-width: 100%;
|
|
93
|
+
padding: 1px 6px;
|
|
94
|
+
border: 1px solid rgba(248, 250, 252, 0.18);
|
|
95
|
+
border-radius: 5px;
|
|
96
|
+
background: rgba(248, 250, 252, 0.1);
|
|
97
|
+
color: #f8fafc;
|
|
98
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
99
|
+
font-size: 11px;
|
|
100
|
+
font-weight: 600;
|
|
101
|
+
line-height: 1.45;
|
|
102
|
+
overflow-wrap: anywhere;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.aimd-field__metadata-host:hover > .aimd-field__metadata-popover,
|
|
106
|
+
.aimd-field__metadata-host:focus > .aimd-field__metadata-popover,
|
|
107
|
+
.aimd-field__metadata-host:focus-within > .aimd-field__metadata-popover {
|
|
108
|
+
opacity: 1;
|
|
109
|
+
visibility: visible;
|
|
110
|
+
transform: translateY(0);
|
|
111
|
+
}
|
package/src/vue/index.ts
CHANGED
|
@@ -12,9 +12,12 @@ export {
|
|
|
12
12
|
createEmbeddedRenderer,
|
|
13
13
|
createMermaidRenderer,
|
|
14
14
|
createStepCardRenderer,
|
|
15
|
+
loadShikiHighlighter,
|
|
16
|
+
type CodeBlockRendererOptions,
|
|
15
17
|
type ElementRenderer,
|
|
16
18
|
hastToVue,
|
|
17
19
|
renderToVNodes,
|
|
20
|
+
type LoadShikiHighlighterOptions,
|
|
18
21
|
type AimdStepCardRendererOptions,
|
|
19
22
|
type ShikiHighlighter,
|
|
20
23
|
type VueRendererOptions,
|