article-content-renderer-vue2 0.3.1 → 0.5.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.
@@ -2,9 +2,9 @@
2
2
  "fileFormat": "article-content-protocol",
3
3
  "fileFormatVersion": 1,
4
4
  "mediaType": "application/vnd.article-content-protocol+json",
5
- "id": "article-content-v1",
5
+ "id": "article-content-v1-with-extensions",
6
6
  "version": 1,
7
- "name": "Article Content Protocol v1",
7
+ "name": "Article Content Protocol v1 + Extensions",
8
8
  "status": "draft",
9
9
  "rootNode": "doc",
10
10
  "nodes": [
@@ -35,13 +35,34 @@
35
35
  "right",
36
36
  "justify"
37
37
  ]
38
+ },
39
+ {
40
+ "name": "anchorId",
41
+ "type": "string",
42
+ "required": false,
43
+ "description": "Stable paragraph/heading anchor, unique within the article."
44
+ },
45
+ {
46
+ "name": "fontSize",
47
+ "type": "integer",
48
+ "required": false,
49
+ "description": "Applied to paragraph.attrs.fontSize alongside the unchanged v1 paragraph attributes. Omit to inherit the default size. Consumers must support this optional extension.",
50
+ "minimum": 8,
51
+ "maximum": 96
38
52
  }
39
53
  ],
40
54
  "render": {
41
55
  "mode": "element",
42
56
  "element": "p",
43
57
  "styleBindings": {
44
- "textAlign": "text-align"
58
+ "textAlign": "text-align",
59
+ "fontSize": "font-size"
60
+ },
61
+ "styleUnits": {
62
+ "fontSize": "px"
63
+ },
64
+ "attributeBindings": {
65
+ "anchorId": "data-anchor-id"
45
66
  }
46
67
  }
47
68
  },
@@ -78,6 +99,12 @@
78
99
  "right",
79
100
  "justify"
80
101
  ]
102
+ },
103
+ {
104
+ "name": "anchorId",
105
+ "type": "string",
106
+ "required": false,
107
+ "description": "Stable paragraph/heading anchor, unique within the article."
81
108
  }
82
109
  ],
83
110
  "render": {
@@ -94,6 +121,9 @@
94
121
  ],
95
122
  "styleBindings": {
96
123
  "textAlign": "text-align"
124
+ },
125
+ "attributeBindings": {
126
+ "anchorId": "data-anchor-id"
97
127
  }
98
128
  }
99
129
  },
@@ -238,6 +268,15 @@
238
268
  "center",
239
269
  "right"
240
270
  ]
271
+ },
272
+ {
273
+ "name": "imageLayout",
274
+ "type": "string",
275
+ "required": false,
276
+ "description": "Applied to image.attrs.imageLayout. Adjacent two-column images flow two per row in document order. Other blocks break the row. Omit for the original full-row image layout.",
277
+ "allowedValues": [
278
+ "two-column"
279
+ ]
241
280
  }
242
281
  ],
243
282
  "render": {
@@ -250,8 +289,14 @@
250
289
  "title": "title",
251
290
  "width": "width",
252
291
  "height": "height",
253
- "imageAlign": "data-image-align"
254
- }
292
+ "imageAlign": "data-image-align",
293
+ "imageLayout": "data-image-layout"
294
+ },
295
+ "layoutNotes": [
296
+ "Constrain display width to the container. When width and height are supplied, scale height proportionally; do not crop the image. Preserve the original dimensions in JSON.",
297
+ "Adjacent sibling images with imageLayout=two-column occupy half a row each, with a gap. Every two images wrap; intervening non-image blocks start a new row. Omit imageLayout for a full-row container.",
298
+ "imageAlign controls horizontal alignment inside the image layout container; omission means center."
299
+ ]
255
300
  }
256
301
  },
257
302
  {
@@ -372,6 +417,58 @@
372
417
  "render": {
373
418
  "mode": "text"
374
419
  }
420
+ },
421
+ {
422
+ "type": "resourceQuestion",
423
+ "description": "Top-level resource question snapshot. Rendering never fetches resource data.",
424
+ "attributes": [
425
+ {
426
+ "name": "id",
427
+ "type": "string",
428
+ "required": true,
429
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.id"
430
+ },
431
+ {
432
+ "name": "resourceId",
433
+ "type": "string",
434
+ "required": true,
435
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.resourceId"
436
+ },
437
+ {
438
+ "name": "title",
439
+ "type": "string",
440
+ "required": true,
441
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.title"
442
+ },
443
+ {
444
+ "name": "description",
445
+ "type": "string",
446
+ "required": true,
447
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.description"
448
+ },
449
+ {
450
+ "name": "options",
451
+ "type": "array",
452
+ "required": true,
453
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.options"
454
+ },
455
+ {
456
+ "name": "hideFollowing",
457
+ "type": "boolean",
458
+ "required": true,
459
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.hideFollowing"
460
+ },
461
+ {
462
+ "name": "revealKey",
463
+ "type": "string",
464
+ "required": true,
465
+ "description": "See documentSchema.definitions.resourceQuestion.properties.attrs.properties.revealKey"
466
+ }
467
+ ],
468
+ "render": {
469
+ "mode": "component",
470
+ "element": "resource-question"
471
+ }
375
472
  }
376
473
  ],
377
474
  "marks": [
@@ -422,13 +519,36 @@
422
519
  },
423
520
  {
424
521
  "type": "link",
425
- "description": "A hyperlink. Renderers must validate and escape the URL.",
522
+ "description": "An href or application-defined custom link.",
426
523
  "attributes": [
524
+ {
525
+ "name": "type",
526
+ "type": "string",
527
+ "required": false,
528
+ "description": "Link destination type. Omission means href for legacy documents.",
529
+ "defaultValue": "href",
530
+ "allowedValues": [
531
+ "href",
532
+ "custom"
533
+ ]
534
+ },
427
535
  {
428
536
  "name": "href",
429
537
  "type": "string",
430
- "required": true,
431
- "description": "Non-empty URI reference; fragment-only links such as # are valid."
538
+ "required": false,
539
+ "description": "Required only for href links. Renderers must validate and escape this URI reference."
540
+ },
541
+ {
542
+ "name": "id",
543
+ "type": "string",
544
+ "required": false,
545
+ "description": "Application-defined identifier required only for custom links."
546
+ },
547
+ {
548
+ "name": "title",
549
+ "type": "string",
550
+ "required": false,
551
+ "description": "Application-defined title required only for custom links."
432
552
  },
433
553
  {
434
554
  "name": "target",
@@ -442,20 +562,73 @@
442
562
  ]
443
563
  }
444
564
  ],
565
+ "constraints": [
566
+ {
567
+ "name": "href-link-fields",
568
+ "description": "An href link requires href and must not contain id or title. A missing type is treated as href."
569
+ },
570
+ {
571
+ "name": "custom-link-fields",
572
+ "description": "A custom link requires type=custom, id, and title, and must not contain href."
573
+ }
574
+ ],
445
575
  "render": {
446
576
  "mode": "element",
447
577
  "element": "a",
448
578
  "attributeBindings": {
579
+ "type": "data-link-type",
449
580
  "href": "href",
581
+ "id": "data-link-id",
582
+ "title": "title",
450
583
  "target": "target"
451
584
  }
452
585
  }
586
+ },
587
+ {
588
+ "type": "textStyle",
589
+ "description": "Text foreground color.",
590
+ "attributes": [
591
+ {
592
+ "name": "color",
593
+ "type": "string",
594
+ "required": true,
595
+ "description": "A six-digit hexadecimal CSS color, including the leading #.",
596
+ "pattern": "^#[0-9a-fA-F]{6}$"
597
+ }
598
+ ],
599
+ "render": {
600
+ "mode": "element",
601
+ "element": "span",
602
+ "styleBindings": {
603
+ "color": "color"
604
+ }
605
+ }
606
+ },
607
+ {
608
+ "type": "highlight",
609
+ "description": "Text background highlight color.",
610
+ "attributes": [
611
+ {
612
+ "name": "color",
613
+ "type": "string",
614
+ "required": true,
615
+ "description": "A six-digit hexadecimal CSS color, including the leading #.",
616
+ "pattern": "^#[0-9a-fA-F]{6}$"
617
+ }
618
+ ],
619
+ "render": {
620
+ "mode": "element",
621
+ "element": "mark",
622
+ "styleBindings": {
623
+ "color": "background-color"
624
+ }
625
+ }
453
626
  }
454
627
  ],
455
628
  "documentSchema": {
456
629
  "$schema": "http://json-schema.org/draft-07/schema#",
457
- "$id": "urn:article-content-protocol:v1",
458
- "title": "Article Content Protocol v1",
630
+ "$id": "urn:article-content-protocol:v1:with-formatting-extensions",
631
+ "title": "Article Content Protocol v1 + Extensions",
459
632
  "type": "object",
460
633
  "additionalProperties": false,
461
634
  "required": [
@@ -469,7 +642,14 @@
469
642
  "content": {
470
643
  "type": "array",
471
644
  "items": {
472
- "$ref": "#/definitions/blockNode"
645
+ "oneOf": [
646
+ {
647
+ "$ref": "#/definitions/blockNode"
648
+ },
649
+ {
650
+ "$ref": "#/definitions/resourceQuestion"
651
+ }
652
+ ]
473
653
  }
474
654
  }
475
655
  },
@@ -524,6 +704,21 @@
524
704
  "properties": {
525
705
  "textAlign": {
526
706
  "$ref": "#/definitions/textAlign"
707
+ },
708
+ "fontSize": {
709
+ "$schema": "http://json-schema.org/draft-07/schema#",
710
+ "$id": "urn:article-content-protocol:paragraph-font-size:v1",
711
+ "title": "Optional paragraph fontSize attribute (pixels)",
712
+ "description": "Applied to paragraph.attrs.fontSize alongside the unchanged v1 paragraph attributes. Omit to inherit the default size. Consumers must support this optional extension.",
713
+ "type": "integer",
714
+ "minimum": 8,
715
+ "maximum": 96
716
+ },
717
+ "anchorId": {
718
+ "type": "string",
719
+ "minLength": 1,
720
+ "pattern": "\\S",
721
+ "description": "Stable paragraph/heading anchor, unique within the article."
527
722
  }
528
723
  }
529
724
  },
@@ -560,6 +755,12 @@
560
755
  },
561
756
  "textAlign": {
562
757
  "$ref": "#/definitions/textAlign"
758
+ },
759
+ "anchorId": {
760
+ "type": "string",
761
+ "minLength": 1,
762
+ "pattern": "\\S",
763
+ "description": "Stable paragraph/heading anchor, unique within the article."
563
764
  }
564
765
  }
565
766
  },
@@ -757,6 +958,16 @@
757
958
  },
758
959
  "imageAlign": {
759
960
  "$ref": "#/definitions/imageAlign"
961
+ },
962
+ "imageLayout": {
963
+ "$schema": "http://json-schema.org/draft-07/schema#",
964
+ "$id": "urn:article-content-protocol:image-layout:v1",
965
+ "title": "Optional two-column image layout",
966
+ "description": "Applied to image.attrs.imageLayout. Adjacent two-column images flow two per row in document order. Other blocks break the row. Omit for the original full-row image layout.",
967
+ "type": "string",
968
+ "enum": [
969
+ "two-column"
970
+ ]
760
971
  }
761
972
  }
762
973
  }
@@ -978,31 +1189,258 @@
978
1189
  "type": {
979
1190
  "const": "link"
980
1191
  },
1192
+ "attrs": {
1193
+ "oneOf": [
1194
+ {
1195
+ "type": "object",
1196
+ "additionalProperties": false,
1197
+ "required": [
1198
+ "href",
1199
+ "target"
1200
+ ],
1201
+ "properties": {
1202
+ "type": {
1203
+ "const": "href",
1204
+ "default": "href",
1205
+ "description": "May be omitted in legacy documents; omission means href."
1206
+ },
1207
+ "href": {
1208
+ "type": "string",
1209
+ "minLength": 1,
1210
+ "description": "Non-empty URI reference; fragment-only links such as # are valid."
1211
+ },
1212
+ "target": {
1213
+ "enum": [
1214
+ "_blank",
1215
+ "_self"
1216
+ ]
1217
+ }
1218
+ }
1219
+ },
1220
+ {
1221
+ "type": "object",
1222
+ "additionalProperties": false,
1223
+ "required": [
1224
+ "type",
1225
+ "id",
1226
+ "title",
1227
+ "target"
1228
+ ],
1229
+ "properties": {
1230
+ "type": {
1231
+ "const": "custom"
1232
+ },
1233
+ "id": {
1234
+ "type": "string",
1235
+ "minLength": 1
1236
+ },
1237
+ "title": {
1238
+ "type": "string",
1239
+ "minLength": 1
1240
+ },
1241
+ "target": {
1242
+ "enum": [
1243
+ "_blank",
1244
+ "_self"
1245
+ ]
1246
+ }
1247
+ }
1248
+ }
1249
+ ]
1250
+ }
1251
+ }
1252
+ },
1253
+ {
1254
+ "$schema": "http://json-schema.org/draft-07/schema#",
1255
+ "$id": "urn:article-content-protocol:text-formatting:v1",
1256
+ "title": "Optional text formatting marks for Article Content Protocol v1",
1257
+ "description": "Additional marks accepted alongside the unchanged v1 marks. Existing v1 documents require no migration. Consumers must support these marks to render colored documents.",
1258
+ "type": "object",
1259
+ "additionalProperties": false,
1260
+ "required": [
1261
+ "type",
1262
+ "attrs"
1263
+ ],
1264
+ "properties": {
1265
+ "type": {
1266
+ "enum": [
1267
+ "textStyle",
1268
+ "highlight"
1269
+ ]
1270
+ },
981
1271
  "attrs": {
982
1272
  "type": "object",
983
1273
  "additionalProperties": false,
984
1274
  "required": [
985
- "href",
986
- "target"
1275
+ "color"
987
1276
  ],
988
1277
  "properties": {
989
- "href": {
1278
+ "color": {
990
1279
  "type": "string",
991
- "minLength": 1,
992
- "description": "Non-empty URI reference; fragment-only links such as # are valid."
993
- },
994
- "target": {
995
- "enum": [
996
- "_blank",
997
- "_self"
998
- ]
1280
+ "pattern": "^#[0-9a-fA-F]{6}$"
999
1281
  }
1000
1282
  }
1001
1283
  }
1002
1284
  }
1003
1285
  }
1004
1286
  ]
1287
+ },
1288
+ "resourceQuestion": {
1289
+ "$id": "urn:article-content-protocol:resource-question:v1",
1290
+ "type": "object",
1291
+ "additionalProperties": false,
1292
+ "required": [
1293
+ "type",
1294
+ "attrs"
1295
+ ],
1296
+ "properties": {
1297
+ "type": {
1298
+ "const": "resourceQuestion"
1299
+ },
1300
+ "attrs": {
1301
+ "type": "object",
1302
+ "additionalProperties": false,
1303
+ "required": [
1304
+ "id",
1305
+ "resourceId",
1306
+ "title",
1307
+ "description",
1308
+ "options",
1309
+ "hideFollowing",
1310
+ "revealKey"
1311
+ ],
1312
+ "properties": {
1313
+ "id": {
1314
+ "type": "string",
1315
+ "minLength": 1,
1316
+ "pattern": "\\S"
1317
+ },
1318
+ "resourceId": {
1319
+ "type": "string"
1320
+ },
1321
+ "title": {
1322
+ "type": "string"
1323
+ },
1324
+ "description": {
1325
+ "type": "string"
1326
+ },
1327
+ "options": {
1328
+ "type": "array",
1329
+ "items": {
1330
+ "type": "object",
1331
+ "additionalProperties": false,
1332
+ "required": [
1333
+ "id",
1334
+ "label"
1335
+ ],
1336
+ "properties": {
1337
+ "id": {
1338
+ "type": "string",
1339
+ "minLength": 1,
1340
+ "pattern": "\\S"
1341
+ },
1342
+ "label": {
1343
+ "type": "string",
1344
+ "minLength": 1,
1345
+ "pattern": "\\S"
1346
+ },
1347
+ "targetAnchorId": {
1348
+ "type": "string",
1349
+ "minLength": 1,
1350
+ "pattern": "\\S"
1351
+ }
1352
+ }
1353
+ }
1354
+ },
1355
+ "hideFollowing": {
1356
+ "type": "boolean"
1357
+ },
1358
+ "revealKey": {
1359
+ "type": "string",
1360
+ "minLength": 1,
1361
+ "pattern": "\\S"
1362
+ }
1363
+ },
1364
+ "allOf": [
1365
+ {
1366
+ "if": {
1367
+ "properties": {
1368
+ "resourceId": {
1369
+ "const": ""
1370
+ }
1371
+ }
1372
+ },
1373
+ "then": {
1374
+ "properties": {
1375
+ "title": {
1376
+ "const": ""
1377
+ },
1378
+ "description": {
1379
+ "const": ""
1380
+ },
1381
+ "options": {
1382
+ "maxItems": 0
1383
+ }
1384
+ }
1385
+ },
1386
+ "else": {
1387
+ "properties": {
1388
+ "resourceId": {
1389
+ "pattern": "\\S"
1390
+ },
1391
+ "title": {
1392
+ "minLength": 1,
1393
+ "pattern": "\\S"
1394
+ },
1395
+ "options": {
1396
+ "minItems": 1
1397
+ }
1398
+ }
1399
+ }
1400
+ }
1401
+ ]
1402
+ }
1403
+ }
1005
1404
  }
1006
1405
  }
1406
+ },
1407
+ "baseProtocol": {
1408
+ "id": "article-content-v1",
1409
+ "version": 1
1410
+ },
1411
+ "extensions": [
1412
+ {
1413
+ "id": "text-formatting",
1414
+ "version": 1,
1415
+ "schemaId": "urn:article-content-protocol:text-formatting:v1"
1416
+ },
1417
+ {
1418
+ "id": "paragraph-font-size",
1419
+ "version": 1,
1420
+ "schemaId": "urn:article-content-protocol:paragraph-font-size:v1"
1421
+ },
1422
+ {
1423
+ "id": "image-layout",
1424
+ "version": 1,
1425
+ "schemaId": "urn:article-content-protocol:image-layout:v1"
1426
+ },
1427
+ {
1428
+ "id": "resource-question",
1429
+ "version": 1,
1430
+ "schemaId": "urn:article-content-protocol:resource-question:v1"
1431
+ },
1432
+ {
1433
+ "id": "paragraph-anchor",
1434
+ "version": 1
1435
+ }
1436
+ ],
1437
+ "resourceQuestionRules": {
1438
+ "data": "Save the selected resourceId, title, description and options as a snapshot. Option IDs are stable strings supplied by the resource. Do not fetch on render.",
1439
+ "identity": "Question id, revealKey and paragraph/heading anchorId must each be unique within the document; option id must be unique within its question. Enforce these semantic checks in addition to JSON Schema.",
1440
+ "draft": "resourceId=\"\" with empty title, description and options is an unconfigured placeholder. Render a neutral placeholder; never unlock automatically.",
1441
+ "placement": "resourceQuestion is allowed only as a direct child of doc.",
1442
+ "navigation": "Match the selected option.targetAnchorId to a paragraph or heading in this article instance. Missing/unbound targets do not navigate. After business-controlled reveal, wait for layout before scrolling.",
1443
+ "visibility": "Scan top-level nodes in order. Include a resourceQuestion, then stop if hideFollowing=true and its revealKey is absent from the host-supplied revealed keys. Recompute from the original document when keys change. Clicking an option does not automatically unlock.",
1444
+ "security": "Visibility is presentation only, not authorization. Hidden article data remains in the JSON; sensitive data must be protected on the server."
1007
1445
  }
1008
1446
  }