@openpresentation/opf 0.13.0 → 0.14.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/README.md +28 -23
- package/dist/{catalogs-ywCamd8C.d.ts → catalogs-D-yyQWCQ.d.ts} +86 -208
- package/dist/catalogs.d.ts +2 -2
- package/dist/catalogs.js +1 -1
- package/dist/{chart-data-Cdr6rRVV.d.ts → chart-data-B_3z9VTb.d.ts} +16 -5
- package/dist/chunk-4LDGKLUC.js +192 -0
- package/dist/{chunk-II5EYKZU.js → chunk-4VJDTF55.js} +2 -92
- package/dist/chunk-5ZU6JAPP.js +83 -0
- package/dist/{chunk-MPM7NRG7.js → chunk-6OXY2CP3.js} +1716 -744
- package/dist/{chunk-IS2CPNVJ.js → chunk-BFLVSVA7.js} +26 -26
- package/dist/chunk-CSQHPVGL.js +94 -0
- package/dist/{chunk-GJKJL4YY.js → chunk-D3TY4TT6.js} +34 -412
- package/dist/chunk-JDJBDYSR.js +4167 -0
- package/dist/{chunk-7QBCWNWL.js → chunk-LS2FMPI5.js} +1086 -1092
- package/dist/{chunk-ATGDDJPX.js → chunk-Q2TCMN56.js} +3 -3
- package/dist/chunk-UPQQD7MA.js +1840 -0
- package/dist/{chunk-RAYB46AB.js → chunk-XIZUK2XM.js} +32 -30
- package/dist/{chunk-E34DJ5LL.js → chunk-XOZ4KMSR.js} +2427 -10820
- package/dist/chunk-Z65B2B77.js +601 -0
- package/dist/{composition-D7we69Tr.d.ts → composition-_WEwBe2a.d.ts} +738 -27
- package/dist/composition.d.ts +2 -2
- package/dist/composition.js +2 -2
- package/dist/convert.d.ts +9 -7
- package/dist/convert.js +33 -19
- package/dist/data.d.ts +4 -4
- package/dist/data.js +3 -3
- package/dist/diff.d.ts +4 -4
- package/dist/diff.js +6 -604
- package/dist/docs.js +54 -42
- package/dist/examples.d.ts +1 -1
- package/dist/examples.js +1366 -2908
- package/dist/finding-C_por275.d.ts +212 -0
- package/dist/format.d.ts +4 -4
- package/dist/format.js +2 -83
- package/dist/index.d.ts +318 -284
- package/dist/index.js +530 -943
- package/dist/markdown.d.ts +28 -27
- package/dist/markdown.js +8 -1940
- package/dist/pagination-BZpXLvFL.d.ts +119 -0
- package/dist/pagination.d.ts +5 -61
- package/dist/pagination.js +5 -5
- package/dist/patch.d.ts +12 -23
- package/dist/patch.js +5 -5
- package/dist/{presentation-mG-IYErQ.d.ts → presentation-C5eHkevA.d.ts} +350 -506
- package/dist/repo-readme.js +1 -1
- package/dist/{schemas-BbPonsTz.d.ts → schemas-DDpqAgyS.d.ts} +31 -17
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +1 -1
- package/dist/spec/README.md +10 -5
- package/dist/spec/catalogs/audiences/index.json +2 -50
- package/dist/spec/catalogs/chart-types/100pct-stacked-area.json +21 -0
- package/dist/spec/catalogs/chart-types/100pct-stacked-bar.json +22 -0
- package/dist/spec/catalogs/chart-types/100pct-stacked-column.json +22 -0
- package/dist/spec/catalogs/chart-types/area.json +2 -60
- package/dist/spec/catalogs/chart-types/bar.json +2 -48
- package/dist/spec/catalogs/chart-types/box-and-whisker.json +2 -132
- package/dist/spec/catalogs/chart-types/column.json +2 -52
- package/dist/spec/catalogs/chart-types/combo.json +37 -0
- package/dist/spec/catalogs/chart-types/doughnut.json +2 -40
- package/dist/spec/catalogs/chart-types/filled-radar.json +2 -52
- package/dist/spec/catalogs/chart-types/funnel.json +2 -46
- package/dist/spec/catalogs/chart-types/histogram.json +2 -149
- package/dist/spec/catalogs/chart-types/index.json +50 -520
- package/dist/spec/catalogs/chart-types/line-with-markers.json +2 -60
- package/dist/spec/catalogs/chart-types/line.json +2 -60
- package/dist/spec/catalogs/chart-types/pareto.json +2 -50
- package/dist/spec/catalogs/chart-types/pie.json +2 -40
- package/dist/spec/catalogs/chart-types/radar-with-markers.json +2 -52
- package/dist/spec/catalogs/chart-types/radar.json +2 -52
- package/dist/spec/catalogs/chart-types/scatter.json +2 -73
- package/dist/spec/catalogs/chart-types/stacked-area.json +21 -0
- package/dist/spec/catalogs/chart-types/stacked-bar.json +22 -0
- package/dist/spec/catalogs/chart-types/stacked-column.json +22 -0
- package/dist/spec/catalogs/chart-types/stacked-line-with-markers.json +22 -0
- package/dist/spec/catalogs/chart-types/stacked-line.json +21 -0
- package/dist/spec/catalogs/chart-types/treemap.json +2 -48
- package/dist/spec/catalogs/chart-types/waterfall.json +2 -52
- package/dist/spec/catalogs/chart-types/world.json +2 -64
- package/dist/spec/catalogs/font-schemes/angsana-new.json +2 -2
- package/dist/spec/catalogs/font-schemes/aparajita.json +3 -3
- package/dist/spec/catalogs/font-schemes/aptos.json +1 -1
- package/dist/spec/catalogs/font-schemes/arabic-typesetting.json +2 -2
- package/dist/spec/catalogs/font-schemes/arial.json +1 -1
- package/dist/spec/catalogs/font-schemes/batang.json +2 -2
- package/dist/spec/catalogs/font-schemes/bookman.json +1 -1
- package/dist/spec/catalogs/font-schemes/calibri.json +1 -1
- package/dist/spec/catalogs/font-schemes/century-schoolbook.json +1 -1
- package/dist/spec/catalogs/font-schemes/consolas.json +2 -4
- package/dist/spec/catalogs/font-schemes/constantia.json +1 -1
- package/dist/spec/catalogs/font-schemes/courier-new.json +2 -4
- package/dist/spec/catalogs/font-schemes/daunpenh.json +2 -2
- package/dist/spec/catalogs/font-schemes/david.json +2 -2
- package/dist/spec/catalogs/font-schemes/dilleniaupc.json +2 -2
- package/dist/spec/catalogs/font-schemes/fangsong.json +2 -2
- package/dist/spec/catalogs/font-schemes/garamond.json +1 -1
- package/dist/spec/catalogs/font-schemes/gautami.json +2 -2
- package/dist/spec/catalogs/font-schemes/georgia.json +1 -1
- package/dist/spec/catalogs/font-schemes/gisha.json +3 -3
- package/dist/spec/catalogs/font-schemes/grandview.json +1 -1
- package/dist/spec/catalogs/font-schemes/gungsuh.json +2 -2
- package/dist/spec/catalogs/font-schemes/impact.json +1 -1
- package/dist/spec/catalogs/font-schemes/index.json +1 -1
- package/dist/spec/catalogs/font-schemes/kalinga.json +2 -2
- package/dist/spec/catalogs/font-schemes/kartika.json +2 -2
- package/dist/spec/catalogs/font-schemes/khmer-ui.json +2 -2
- package/dist/spec/catalogs/font-schemes/latha.json +2 -2
- package/dist/spec/catalogs/font-schemes/lucida-sans.json +1 -1
- package/dist/spec/catalogs/font-schemes/malgun-gothic.json +2 -2
- package/dist/spec/catalogs/font-schemes/mangal.json +4 -5
- package/dist/spec/catalogs/font-schemes/meiryo.json +2 -2
- package/dist/spec/catalogs/font-schemes/microsoft-jhenghei.json +2 -2
- package/dist/spec/catalogs/font-schemes/microsoft-yahei.json +5 -5
- package/dist/spec/catalogs/font-schemes/mingliu.json +2 -2
- package/dist/spec/catalogs/font-schemes/miriam.json +2 -2
- package/dist/spec/catalogs/font-schemes/montserrat.json +1 -1
- package/dist/spec/catalogs/font-schemes/ms-mincho.json +2 -2
- package/dist/spec/catalogs/font-schemes/nirmala-ui.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-naksh-arabic.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-nastaliq-urdu.json +3 -3
- package/dist/spec/catalogs/font-schemes/noto-sans-arabic.json +4 -4
- package/dist/spec/catalogs/font-schemes/noto-sans-armenian.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-bengali.json +3 -3
- package/dist/spec/catalogs/font-schemes/noto-sans-devangari.json +3 -3
- package/dist/spec/catalogs/font-schemes/noto-sans-ethiopic.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-georgian.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-gujarati.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-gurmukhi.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-hebrew.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-jp.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-kannada.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-khmer.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-kr.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-malayalam.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-mongolian.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-oriya.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-sc.json +5 -5
- package/dist/spec/catalogs/font-schemes/noto-sans-tamil.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-tc.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-telugu.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans-thai.json +2 -2
- package/dist/spec/catalogs/font-schemes/noto-sans.json +5 -5
- package/dist/spec/catalogs/font-schemes/nyala.json +2 -2
- package/dist/spec/catalogs/font-schemes/open-sans.json +1 -1
- package/dist/spec/catalogs/font-schemes/pmingliu.json +2 -2
- package/dist/spec/catalogs/font-schemes/poppins.json +1 -1
- package/dist/spec/catalogs/font-schemes/pt-serif.json +1 -1
- package/dist/spec/catalogs/font-schemes/raavi.json +2 -2
- package/dist/spec/catalogs/font-schemes/raleway.json +1 -1
- package/dist/spec/catalogs/font-schemes/roboto.json +1 -1
- package/dist/spec/catalogs/font-schemes/rockwell.json +1 -1
- package/dist/spec/catalogs/font-schemes/sakkal-majalla.json +4 -4
- package/dist/spec/catalogs/font-schemes/seaford.json +1 -1
- package/dist/spec/catalogs/font-schemes/segoe-ui-light.json +1 -1
- package/dist/spec/catalogs/font-schemes/segoe-ui.json +1 -1
- package/dist/spec/catalogs/font-schemes/shonar-bangla.json +3 -3
- package/dist/spec/catalogs/font-schemes/shruti.json +2 -2
- package/dist/spec/catalogs/font-schemes/simsun.json +2 -2
- package/dist/spec/catalogs/font-schemes/skeena.json +1 -1
- package/dist/spec/catalogs/font-schemes/sylfaen.json +3 -3
- package/dist/spec/catalogs/font-schemes/tahoma.json +1 -1
- package/dist/spec/catalogs/font-schemes/tenorite.json +1 -1
- package/dist/spec/catalogs/font-schemes/times-new-roman.json +1 -1
- package/dist/spec/catalogs/font-schemes/traditional-arabic.json +4 -4
- package/dist/spec/catalogs/font-schemes/trebuchet-ms.json +1 -1
- package/dist/spec/catalogs/font-schemes/tunga.json +2 -2
- package/dist/spec/catalogs/font-schemes/verdana.json +1 -1
- package/dist/spec/catalogs/font-schemes/vrinda.json +2 -2
- package/dist/spec/catalogs/font-schemes/yu-gothic.json +2 -2
- package/dist/spec/catalogs/layouts/action-plan.json +9 -15
- package/dist/spec/catalogs/layouts/agenda.json +8 -15
- package/dist/spec/catalogs/layouts/appendix-index.json +7 -15
- package/dist/spec/catalogs/layouts/architecture-stack.json +9 -15
- package/dist/spec/catalogs/layouts/assumptions-dependencies.json +9 -15
- package/dist/spec/catalogs/layouts/before-after.json +9 -15
- package/dist/spec/catalogs/layouts/benchmark-target-table.json +9 -15
- package/dist/spec/catalogs/layouts/blank.json +11 -1
- package/dist/spec/catalogs/layouts/bullet-list.json +9 -15
- package/dist/spec/catalogs/layouts/business-model-canvas.json +9 -15
- package/dist/spec/catalogs/layouts/capability-map.json +14 -16
- package/dist/spec/catalogs/layouts/case-study.json +9 -15
- package/dist/spec/catalogs/layouts/chapter-recap.json +8 -15
- package/dist/spec/catalogs/layouts/chart-1x.json +15 -0
- package/dist/spec/catalogs/layouts/chart-2x.json +15 -0
- package/dist/spec/catalogs/layouts/chart-3x.json +15 -0
- package/dist/spec/catalogs/layouts/circular-lifecycle.json +9 -15
- package/dist/spec/catalogs/layouts/code-1x.json +10 -0
- package/dist/spec/catalogs/layouts/comparison.json +9 -15
- package/dist/spec/catalogs/layouts/competitive-landscape.json +14 -16
- package/dist/spec/catalogs/layouts/customer-journey.json +14 -16
- package/dist/spec/catalogs/layouts/customer-logos.json +9 -15
- package/dist/spec/catalogs/layouts/dashboard.json +9 -15
- package/dist/spec/catalogs/layouts/data-visualization.json +9 -15
- package/dist/spec/catalogs/layouts/decision-tree.json +14 -16
- package/dist/spec/catalogs/layouts/detailed-data-table.json +9 -15
- package/dist/spec/catalogs/layouts/ecosystem-map.json +14 -16
- package/dist/spec/catalogs/layouts/executive-decision.json +9 -15
- package/dist/spec/catalogs/layouts/executive-summary.json +9 -15
- package/dist/spec/catalogs/layouts/extract/canonical.json +8 -8
- package/dist/spec/catalogs/layouts/faq.json +9 -15
- package/dist/spec/catalogs/layouts/feature-comparison-matrix.json +9 -15
- package/dist/spec/catalogs/layouts/forecast-scenario.json +9 -15
- package/dist/spec/catalogs/layouts/funnel-pyramid.json +9 -15
- package/dist/spec/catalogs/layouts/gantt-project-plan.json +9 -15
- package/dist/spec/catalogs/layouts/geographic-map.json +13 -15
- package/dist/spec/catalogs/layouts/heatmap-cohort.json +9 -15
- package/dist/spec/catalogs/layouts/hub-and-spoke.json +9 -15
- package/dist/spec/catalogs/layouts/icon-grid.json +14 -16
- package/dist/spec/catalogs/layouts/image-1x.json +11 -1
- package/dist/spec/catalogs/layouts/image-2x.json +12 -2
- package/dist/spec/catalogs/layouts/image-3x.json +13 -3
- package/dist/spec/catalogs/layouts/image-bleed.json +12 -2
- package/dist/spec/catalogs/layouts/image-focus.json +14 -16
- package/dist/spec/catalogs/layouts/index.json +1 -1
- package/dist/spec/catalogs/layouts/key-takeaway.json +8 -15
- package/dist/spec/catalogs/layouts/kpi-scorecard.json +9 -15
- package/dist/spec/catalogs/layouts/list-1x.json +17 -1
- package/dist/spec/catalogs/layouts/list-2x.json +16 -0
- package/dist/spec/catalogs/layouts/list-3x.json +16 -0
- package/dist/spec/catalogs/layouts/list-4x.json +16 -0
- package/dist/spec/catalogs/layouts/list-5x.json +16 -0
- package/dist/spec/catalogs/layouts/list-6x.json +16 -0
- package/dist/spec/catalogs/layouts/logic-tree.json +9 -15
- package/dist/spec/catalogs/layouts/market-size.json +9 -15
- package/dist/spec/catalogs/layouts/matrix-quadrant.json +9 -15
- package/dist/spec/catalogs/layouts/media-1x.json +11 -1
- package/dist/spec/catalogs/layouts/network-dependency-map.json +13 -15
- package/dist/spec/catalogs/layouts/number-1x.json +16 -1
- package/dist/spec/catalogs/layouts/number-2x.json +15 -0
- package/dist/spec/catalogs/layouts/number-3x.json +15 -0
- package/dist/spec/catalogs/layouts/number-4x.json +15 -0
- package/dist/spec/catalogs/layouts/number-5x.json +15 -0
- package/dist/spec/catalogs/layouts/number-6x.json +15 -0
- package/dist/spec/catalogs/layouts/one-column-explainer.json +9 -15
- package/dist/spec/catalogs/layouts/org-chart.json +9 -15
- package/dist/spec/catalogs/layouts/persona-grid.json +14 -16
- package/dist/spec/catalogs/layouts/photo-grid.json +17 -19
- package/dist/spec/catalogs/layouts/pricing-table.json +9 -15
- package/dist/spec/catalogs/layouts/process-flow.json +9 -15
- package/dist/spec/catalogs/layouts/product-feature.json +14 -16
- package/dist/spec/catalogs/layouts/pros-cons.json +9 -15
- package/dist/spec/catalogs/layouts/qa-discussion.json +7 -15
- package/dist/spec/catalogs/layouts/quote-1x.json +11 -1
- package/dist/spec/catalogs/layouts/quote-highlight.json +9 -15
- package/dist/spec/catalogs/layouts/raci-matrix.json +9 -15
- package/dist/spec/catalogs/layouts/risk-heatmap.json +9 -15
- package/dist/spec/catalogs/layouts/roadmap.json +9 -15
- package/dist/spec/catalogs/layouts/screenshot-walkthrough.json +14 -16
- package/dist/spec/catalogs/layouts/section-divider.json +8 -15
- package/dist/spec/catalogs/layouts/single-message-statement.json +8 -15
- package/dist/spec/catalogs/layouts/stats-metrics.json +9 -15
- package/dist/spec/catalogs/layouts/status-rag.json +9 -15
- package/dist/spec/catalogs/layouts/swimlane-process.json +14 -16
- package/dist/spec/catalogs/layouts/swot-analysis.json +9 -15
- package/dist/spec/catalogs/layouts/table-1x.json +10 -0
- package/dist/spec/catalogs/layouts/team-bio.json +14 -16
- package/dist/spec/catalogs/layouts/testimonial-grid.json +9 -15
- package/dist/spec/catalogs/layouts/text-1x.json +11 -1
- package/dist/spec/catalogs/layouts/text-2x.json +10 -0
- package/dist/spec/catalogs/layouts/text-3x.json +10 -0
- package/dist/spec/catalogs/layouts/thank-you-cta.json +8 -15
- package/dist/spec/catalogs/layouts/three-column.json +9 -15
- package/dist/spec/catalogs/layouts/timeline-1x.json +11 -1
- package/dist/spec/catalogs/layouts/timeline.json +9 -15
- package/dist/spec/catalogs/layouts/title-slide.json +8 -15
- package/dist/spec/catalogs/layouts/title-subtitle.json +11 -1
- package/dist/spec/catalogs/layouts/title.json +11 -1
- package/dist/spec/catalogs/layouts/two-column.json +9 -15
- package/dist/spec/catalogs/layouts/venn-overlap.json +9 -15
- package/dist/spec/catalogs/layouts/waterfall-bridge.json +9 -15
- package/dist/spec/catalogs/layouts/wheel-radial.json +9 -15
- package/dist/spec/catalogs/manifest.json +8 -8
- package/dist/spec/catalogs/narratives/board-meeting.json +45 -45
- package/dist/spec/catalogs/narratives/business-narrative.json +19 -19
- package/dist/spec/catalogs/narratives/business-review.json +27 -27
- package/dist/spec/catalogs/narratives/capacity-planning.json +19 -19
- package/dist/spec/catalogs/narratives/challenge-resolution.json +17 -17
- package/dist/spec/catalogs/narratives/change-story.json +13 -13
- package/dist/spec/catalogs/narratives/classic-story.json +17 -17
- package/dist/spec/catalogs/narratives/company-intro.json +21 -21
- package/dist/spec/catalogs/narratives/conference-talk.json +4 -4
- package/dist/spec/catalogs/narratives/data-story.json +13 -14
- package/dist/spec/catalogs/narratives/early-startup-pitch.json +27 -27
- package/dist/spec/catalogs/narratives/educate.json +21 -21
- package/dist/spec/catalogs/narratives/employee-review.json +19 -19
- package/dist/spec/catalogs/narratives/failure-analysis.json +23 -23
- package/dist/spec/catalogs/narratives/focus.json +27 -27
- package/dist/spec/catalogs/narratives/golden-circle.json +4 -4
- package/dist/spec/catalogs/narratives/heros-journey.json +13 -13
- package/dist/spec/catalogs/narratives/index.json +145 -145
- package/dist/spec/catalogs/narratives/innovation.json +21 -21
- package/dist/spec/catalogs/narratives/justice.json +25 -25
- package/dist/spec/catalogs/narratives/marketing-strategy.json +25 -25
- package/dist/spec/catalogs/narratives/performance-improvement-plan.json +19 -19
- package/dist/spec/catalogs/narratives/performance-review.json +25 -25
- package/dist/spec/catalogs/narratives/persuade.json +17 -17
- package/dist/spec/catalogs/narratives/persuasive-sales.json +19 -19
- package/dist/spec/catalogs/narratives/pitch-deck.json +6 -6
- package/dist/spec/catalogs/narratives/problem-solution.json +5 -5
- package/dist/spec/catalogs/narratives/product-launch.json +23 -23
- package/dist/spec/catalogs/narratives/project-proposal.json +23 -23
- package/dist/spec/catalogs/narratives/pyramid-principle.json +9 -9
- package/dist/spec/catalogs/narratives/qbr.json +8 -8
- package/dist/spec/catalogs/narratives/rags-to-riches.json +17 -17
- package/dist/spec/catalogs/narratives/reveal.json +19 -19
- package/dist/spec/catalogs/narratives/scqa.json +4 -4
- package/dist/spec/catalogs/narratives/situation-complication-resolution.json +11 -11
- package/dist/spec/catalogs/narratives/sparkline.json +11 -11
- package/dist/spec/catalogs/narratives/star-method.json +11 -11
- package/dist/spec/catalogs/narratives/status-update.json +15 -15
- package/dist/spec/catalogs/narratives/strategic-advisory.json +17 -17
- package/dist/spec/catalogs/narratives/strategic-narrative.json +4 -4
- package/dist/spec/catalogs/narratives/survey-analysis.json +23 -23
- package/dist/spec/catalogs/narratives/survival-story.json +23 -23
- package/dist/spec/catalogs/narratives/transformation-arc.json +4 -4
- package/dist/spec/catalogs/narratives/trend-analysis.json +17 -17
- package/dist/spec/catalogs/narratives/underdog-victory.json +19 -19
- package/dist/spec/catalogs/narratives/venture-pitch.json +27 -27
- package/dist/spec/catalogs/narratives/vision-roadmap.json +13 -13
- package/dist/spec/catalogs/narratives/weekly-progress.json +23 -23
- package/dist/spec/catalogs/narratives/what-so-what-now-what.json +9 -9
- package/dist/spec/openapi.yaml +2 -5
- package/dist/spec/reference/engine-defaults.json +2 -2
- package/dist/spec/schemas/audience.schema.json +1 -1
- package/dist/spec/schemas/catalog-index.schema.json +2 -2
- package/dist/spec/schemas/chart-type.schema.json +19 -290
- package/dist/spec/schemas/color-scheme.schema.json +20 -12
- package/dist/spec/schemas/finding.schema.json +191 -0
- package/dist/spec/schemas/font-scheme.schema.json +19 -46
- package/dist/spec/schemas/layout.schema.json +100 -159
- package/dist/spec/schemas/narrative.schema.json +17 -25
- package/dist/spec/schemas/opf.schema.json +286 -340
- package/dist/spec/schemas/social-platform.schema.json +1 -26
- package/dist/spec/schemas/theme.schema.json +4 -1
- package/dist/spec-files.d.ts +1 -1
- package/dist/spec-files.js +1 -1
- package/dist/symbol-font-encodings.js +18448 -1
- package/dist/types.d.ts +4 -4
- package/dist/validation-types-zh03LeZy.d.ts +276 -0
- package/dist/validator.d.ts +60 -4
- package/dist/validator.js +4 -4
- package/dist/yaml.d.ts +87 -0
- package/dist/yaml.js +321 -0
- package/package.json +5 -9
- package/dist/audit.d.ts +0 -35
- package/dist/audit.js +0 -7
- package/dist/chunk-7N4VMAT4.js +0 -1694
- package/dist/chunk-FYLJVF7X.js +0 -18448
- package/dist/chunk-INU7ZNSB.js +0 -670
- package/dist/chunk-IYCJUKWD.js +0 -951
- package/dist/lint-B7azdiuE.d.ts +0 -197
- package/dist/lint.d.ts +0 -7
- package/dist/lint.js +0 -6
- package/dist/spec/catalogs/audiences/customers.json +0 -27
- package/dist/spec/catalogs/audiences/executives.json +0 -27
- package/dist/spec/catalogs/audiences/investors.json +0 -27
- package/dist/spec/catalogs/audiences/marketing-team.json +0 -27
- package/dist/spec/catalogs/audiences/regulators.json +0 -27
- package/dist/spec/catalogs/audiences/sales-team.json +0 -27
- package/dist/spec/catalogs/chart-types/100pct-bullet-bar-2x.json +0 -91
- package/dist/spec/catalogs/chart-types/100pct-bullet-bar-3x.json +0 -103
- package/dist/spec/catalogs/chart-types/100pct-bullet-bar.json +0 -79
- package/dist/spec/catalogs/chart-types/100pct-bullet-column-2x.json +0 -91
- package/dist/spec/catalogs/chart-types/100pct-bullet-column-3x.json +0 -103
- package/dist/spec/catalogs/chart-types/100pct-bullet-column.json +0 -79
- package/dist/spec/catalogs/chart-types/100pct-progress-bar.json +0 -105
- package/dist/spec/catalogs/chart-types/100pct-stacked-area-2x.json +0 -106
- package/dist/spec/catalogs/chart-types/100pct-stacked-area-3x.json +0 -123
- package/dist/spec/catalogs/chart-types/100pct-stacked-bar-2x.json +0 -89
- package/dist/spec/catalogs/chart-types/100pct-stacked-bar-3x.json +0 -100
- package/dist/spec/catalogs/chart-types/100pct-stacked-column-2x.json +0 -95
- package/dist/spec/catalogs/chart-types/100pct-stacked-column-3x.json +0 -108
- package/dist/spec/catalogs/chart-types/australia.json +0 -76
- package/dist/spec/catalogs/chart-types/box-and-whisker-2x.json +0 -136
- package/dist/spec/catalogs/chart-types/box-and-whisker-3x.json +0 -168
- package/dist/spec/catalogs/chart-types/bullet-bar-2x.json +0 -89
- package/dist/spec/catalogs/chart-types/bullet-bar-3x.json +0 -101
- package/dist/spec/catalogs/chart-types/bullet-bar.json +0 -77
- package/dist/spec/catalogs/chart-types/bullet-column-2x.json +0 -89
- package/dist/spec/catalogs/chart-types/bullet-column-3x.json +0 -101
- package/dist/spec/catalogs/chart-types/bullet-column.json +0 -77
- package/dist/spec/catalogs/chart-types/canada.json +0 -86
- package/dist/spec/catalogs/chart-types/clustered-bar-2x.json +0 -89
- package/dist/spec/catalogs/chart-types/clustered-column.json +0 -95
- package/dist/spec/catalogs/chart-types/dot-plot-2x.json +0 -99
- package/dist/spec/catalogs/chart-types/dot-plot-3x.json +0 -124
- package/dist/spec/catalogs/chart-types/dot-plot-4x.json +0 -149
- package/dist/spec/catalogs/chart-types/dot-plot-5x.json +0 -174
- package/dist/spec/catalogs/chart-types/dot-plot-6x.json +0 -199
- package/dist/spec/catalogs/chart-types/dot-plot.json +0 -74
- package/dist/spec/catalogs/chart-types/dumbbell.json +0 -120
- package/dist/spec/catalogs/chart-types/line-2x.json +0 -105
- package/dist/spec/catalogs/chart-types/line-3x.json +0 -127
- package/dist/spec/catalogs/chart-types/line-with-high-low-and-markers.json +0 -144
- package/dist/spec/catalogs/chart-types/line-with-high-low.json +0 -144
- package/dist/spec/catalogs/chart-types/line-with-markers-2x.json +0 -106
- package/dist/spec/catalogs/chart-types/line-with-markers-3x.json +0 -128
- package/dist/spec/catalogs/chart-types/sparkline-2x.json +0 -138
- package/dist/spec/catalogs/chart-types/sparkline-3x.json +0 -174
- package/dist/spec/catalogs/chart-types/sparkline-4x.json +0 -210
- package/dist/spec/catalogs/chart-types/sparkline-5x.json +0 -246
- package/dist/spec/catalogs/chart-types/sparkline-6x.json +0 -282
- package/dist/spec/catalogs/chart-types/sparkline.json +0 -102
- package/dist/spec/catalogs/chart-types/stacked-area-2x.json +0 -106
- package/dist/spec/catalogs/chart-types/stacked-area-3x.json +0 -123
- package/dist/spec/catalogs/chart-types/stacked-bar-2x.json +0 -89
- package/dist/spec/catalogs/chart-types/stacked-bar-3x.json +0 -100
- package/dist/spec/catalogs/chart-types/stacked-column-2x.json +0 -95
- package/dist/spec/catalogs/chart-types/stacked-column-3x.json +0 -108
- package/dist/spec/catalogs/chart-types/stacked-line-2x.json +0 -106
- package/dist/spec/catalogs/chart-types/stacked-line-3x.json +0 -123
- package/dist/spec/catalogs/chart-types/stacked-line-with-markers-2x.json +0 -107
- package/dist/spec/catalogs/chart-types/stacked-line-with-markers-3x.json +0 -124
- package/dist/spec/catalogs/chart-types/treemap-2x.json +0 -101
- package/dist/spec/catalogs/chart-types/treemap-3x.json +0 -122
- package/dist/spec/catalogs/chart-types/united-kingdom.json +0 -68
- package/dist/spec/catalogs/chart-types/united-states.json +0 -82
- package/dist/validator-CIylxoIm.d.ts +0 -172
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { catalogs } from './chunk-
|
|
1
|
+
import { catalogs } from './chunk-XOZ4KMSR.js';
|
|
2
2
|
|
|
3
3
|
// src/table.ts
|
|
4
4
|
var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
@@ -7,7 +7,7 @@ function tableGrid(value, path = "table") {
|
|
|
7
7
|
const values = [...hasHeaders ? [table.columns] : [], ...Array.isArray(table.rows) ? table.rows : []];
|
|
8
8
|
const columnCount = values.reduce((count, row) => Math.max(count, Array.isArray(row) ? row.length : 0), 1), rowCount = values.length;
|
|
9
9
|
const owners = Array.from({ length: rowCount }, () => Array(columnCount));
|
|
10
|
-
const
|
|
10
|
+
const rows3 = Array.from({ length: rowCount }, () => []), issues = [];
|
|
11
11
|
const location = (r, c) => `${path}.${hasHeaders && r === 0 ? "columns" : `rows.${r - Number(hasHeaders)}`}.${c}`;
|
|
12
12
|
for (let r = 0; r < rowCount; r++) for (let c = 0; c < columnCount; c++) {
|
|
13
13
|
const input = values[r]?.[c], cellPath = location(r, c), existing = owners[r][c];
|
|
@@ -15,21 +15,21 @@ function tableGrid(value, path = "table") {
|
|
|
15
15
|
if (input !== null) issues.push({ path: cellPath, message: "A position covered by a spanning cell must explicitly contain null; content cannot be hidden." });
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
const column = !styled && hasHeaders && r === 0 && typeof
|
|
20
|
-
const rowSpan = styled ?
|
|
18
|
+
const object2 = record(input), styled = Object.hasOwn(object2, "value");
|
|
19
|
+
const column = !styled && hasHeaders && r === 0 && typeof object2.name === "string";
|
|
20
|
+
const rowSpan = styled ? object2.rowSpan ?? 1 : 1, colSpan = styled ? object2.colSpan ?? 1 : 1;
|
|
21
21
|
if (!Number.isSafeInteger(rowSpan) || !Number.isSafeInteger(colSpan) || rowSpan < 1 || colSpan < 1 || r + rowSpan > rowCount || c + colSpan > columnCount || hasHeaders && r === 0 && rowSpan > 1) {
|
|
22
22
|
issues.push({ path: cellPath, message: "Cell spans must be positive integers within the table grid and cannot cross from headers into body rows." });
|
|
23
23
|
continue;
|
|
24
24
|
}
|
|
25
|
-
const cell = { input, value: styled ?
|
|
26
|
-
|
|
25
|
+
const cell = { input, value: styled ? object2.value : column ? object2.name : input, style: styled ? record(object2.style) : {}, row: r, column: c, rowSpan, colSpan, header: hasHeaders && r === 0, path: cellPath, valuePath: styled ? cellPath + ".value" : column ? cellPath + ".name" : cellPath };
|
|
26
|
+
rows3[r].push(cell);
|
|
27
27
|
for (let y = r; y < r + rowSpan; y++) for (let x = c; x < c + colSpan; x++) {
|
|
28
28
|
if (owners[y][x]) issues.push({ path: cellPath, message: "Cell spans cannot overlap another spanning cell." });
|
|
29
29
|
else owners[y][x] = cell;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
return { rows:
|
|
32
|
+
return { rows: rows3, columnCount, rowCount, hasHeaders, owners, issues };
|
|
33
33
|
}
|
|
34
34
|
function tableRowBoundaries(value) {
|
|
35
35
|
const grid = tableGrid(value), offset = Number(grid.hasHeaders), count = grid.rowCount - offset;
|
|
@@ -38,562 +38,6 @@ function tableRowBoundaries(value) {
|
|
|
38
38
|
return [...allowed];
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// src/generated/catalog-ids.ts
|
|
42
|
-
var catalogIds = {
|
|
43
|
-
audiences: [
|
|
44
|
-
"executives",
|
|
45
|
-
"board",
|
|
46
|
-
"engineering-team",
|
|
47
|
-
"investors",
|
|
48
|
-
"customers",
|
|
49
|
-
"sales-team",
|
|
50
|
-
"marketing-team",
|
|
51
|
-
"all-hands",
|
|
52
|
-
"candidates",
|
|
53
|
-
"regulators",
|
|
54
|
-
"executive",
|
|
55
|
-
"investor",
|
|
56
|
-
"technical",
|
|
57
|
-
"sales",
|
|
58
|
-
"marketing",
|
|
59
|
-
"academic",
|
|
60
|
-
"internal-team",
|
|
61
|
-
"customer",
|
|
62
|
-
"general-public",
|
|
63
|
-
"media",
|
|
64
|
-
"partner",
|
|
65
|
-
"regulatory"
|
|
66
|
-
],
|
|
67
|
-
purposes: [
|
|
68
|
-
"inform",
|
|
69
|
-
"decide",
|
|
70
|
-
"align",
|
|
71
|
-
"persuade",
|
|
72
|
-
"educate",
|
|
73
|
-
"report",
|
|
74
|
-
"pitch",
|
|
75
|
-
"sell",
|
|
76
|
-
"plan"
|
|
77
|
-
],
|
|
78
|
-
tones: [
|
|
79
|
-
"formal",
|
|
80
|
-
"casual",
|
|
81
|
-
"inspirational",
|
|
82
|
-
"technical",
|
|
83
|
-
"persuasive",
|
|
84
|
-
"authoritative",
|
|
85
|
-
"conversational"
|
|
86
|
-
],
|
|
87
|
-
themes: [
|
|
88
|
-
"minimal",
|
|
89
|
-
"classic",
|
|
90
|
-
"dark",
|
|
91
|
-
"bold"
|
|
92
|
-
],
|
|
93
|
-
layouts: [
|
|
94
|
-
"blank",
|
|
95
|
-
"chart-1x",
|
|
96
|
-
"chart-2x",
|
|
97
|
-
"chart-3x",
|
|
98
|
-
"code-1x",
|
|
99
|
-
"image-1x",
|
|
100
|
-
"image-2x",
|
|
101
|
-
"image-3x",
|
|
102
|
-
"image-bleed",
|
|
103
|
-
"list-1x",
|
|
104
|
-
"list-2x",
|
|
105
|
-
"list-3x",
|
|
106
|
-
"list-4x",
|
|
107
|
-
"list-5x",
|
|
108
|
-
"list-6x",
|
|
109
|
-
"media-1x",
|
|
110
|
-
"number-1x",
|
|
111
|
-
"number-2x",
|
|
112
|
-
"number-3x",
|
|
113
|
-
"number-4x",
|
|
114
|
-
"number-5x",
|
|
115
|
-
"number-6x",
|
|
116
|
-
"quote-1x",
|
|
117
|
-
"table-1x",
|
|
118
|
-
"text-1x",
|
|
119
|
-
"text-2x",
|
|
120
|
-
"text-3x",
|
|
121
|
-
"timeline-1x",
|
|
122
|
-
"title",
|
|
123
|
-
"title-subtitle",
|
|
124
|
-
"title-slide",
|
|
125
|
-
"two-column",
|
|
126
|
-
"image-focus",
|
|
127
|
-
"data-visualization",
|
|
128
|
-
"quote-highlight",
|
|
129
|
-
"section-divider",
|
|
130
|
-
"agenda",
|
|
131
|
-
"thank-you-cta",
|
|
132
|
-
"bullet-list",
|
|
133
|
-
"three-column",
|
|
134
|
-
"icon-grid",
|
|
135
|
-
"faq",
|
|
136
|
-
"stats-metrics",
|
|
137
|
-
"comparison",
|
|
138
|
-
"swot-analysis",
|
|
139
|
-
"matrix-quadrant",
|
|
140
|
-
"funnel-pyramid",
|
|
141
|
-
"timeline",
|
|
142
|
-
"process-flow",
|
|
143
|
-
"photo-grid",
|
|
144
|
-
"before-after",
|
|
145
|
-
"testimonial-grid",
|
|
146
|
-
"team-bio",
|
|
147
|
-
"pricing-table",
|
|
148
|
-
"roadmap",
|
|
149
|
-
"product-feature",
|
|
150
|
-
"executive-summary",
|
|
151
|
-
"key-takeaway",
|
|
152
|
-
"chapter-recap",
|
|
153
|
-
"qa-discussion",
|
|
154
|
-
"single-message-statement",
|
|
155
|
-
"one-column-explainer",
|
|
156
|
-
"case-study",
|
|
157
|
-
"pros-cons",
|
|
158
|
-
"feature-comparison-matrix",
|
|
159
|
-
"venn-overlap",
|
|
160
|
-
"decision-tree",
|
|
161
|
-
"kpi-scorecard",
|
|
162
|
-
"dashboard",
|
|
163
|
-
"waterfall-bridge",
|
|
164
|
-
"benchmark-target-table",
|
|
165
|
-
"heatmap-cohort",
|
|
166
|
-
"risk-heatmap",
|
|
167
|
-
"forecast-scenario",
|
|
168
|
-
"swimlane-process",
|
|
169
|
-
"gantt-project-plan",
|
|
170
|
-
"circular-lifecycle",
|
|
171
|
-
"customer-journey",
|
|
172
|
-
"org-chart",
|
|
173
|
-
"capability-map",
|
|
174
|
-
"logic-tree",
|
|
175
|
-
"hub-and-spoke",
|
|
176
|
-
"architecture-stack",
|
|
177
|
-
"ecosystem-map",
|
|
178
|
-
"network-dependency-map",
|
|
179
|
-
"wheel-radial",
|
|
180
|
-
"geographic-map",
|
|
181
|
-
"screenshot-walkthrough",
|
|
182
|
-
"market-size",
|
|
183
|
-
"persona-grid",
|
|
184
|
-
"competitive-landscape",
|
|
185
|
-
"business-model-canvas",
|
|
186
|
-
"customer-logos",
|
|
187
|
-
"executive-decision",
|
|
188
|
-
"status-rag",
|
|
189
|
-
"raci-matrix",
|
|
190
|
-
"action-plan",
|
|
191
|
-
"assumptions-dependencies",
|
|
192
|
-
"appendix-index",
|
|
193
|
-
"detailed-data-table"
|
|
194
|
-
],
|
|
195
|
-
chartTypes: [
|
|
196
|
-
"100pct-stacked-area-3x",
|
|
197
|
-
"100pct-stacked-bar-3x",
|
|
198
|
-
"100pct-stacked-column-3x",
|
|
199
|
-
"area",
|
|
200
|
-
"bar",
|
|
201
|
-
"box-and-whisker",
|
|
202
|
-
"column",
|
|
203
|
-
"doughnut",
|
|
204
|
-
"filled-radar",
|
|
205
|
-
"funnel",
|
|
206
|
-
"histogram",
|
|
207
|
-
"line",
|
|
208
|
-
"line-with-markers",
|
|
209
|
-
"pareto",
|
|
210
|
-
"pie",
|
|
211
|
-
"radar",
|
|
212
|
-
"radar-with-markers",
|
|
213
|
-
"scatter",
|
|
214
|
-
"stacked-area-3x",
|
|
215
|
-
"stacked-bar-3x",
|
|
216
|
-
"stacked-column-3x",
|
|
217
|
-
"stacked-line-3x",
|
|
218
|
-
"stacked-line-with-markers-3x",
|
|
219
|
-
"treemap",
|
|
220
|
-
"waterfall",
|
|
221
|
-
"world",
|
|
222
|
-
"100pct-bullet-bar",
|
|
223
|
-
"100pct-bullet-bar-2x",
|
|
224
|
-
"100pct-bullet-bar-3x",
|
|
225
|
-
"100pct-bullet-column",
|
|
226
|
-
"100pct-bullet-column-2x",
|
|
227
|
-
"100pct-bullet-column-3x",
|
|
228
|
-
"100pct-progress-bar",
|
|
229
|
-
"100pct-stacked-area-2x",
|
|
230
|
-
"100pct-stacked-bar-2x",
|
|
231
|
-
"100pct-stacked-column-2x",
|
|
232
|
-
"australia",
|
|
233
|
-
"box-and-whisker-2x",
|
|
234
|
-
"box-and-whisker-3x",
|
|
235
|
-
"bullet-bar",
|
|
236
|
-
"bullet-bar-2x",
|
|
237
|
-
"bullet-bar-3x",
|
|
238
|
-
"bullet-column",
|
|
239
|
-
"bullet-column-2x",
|
|
240
|
-
"bullet-column-3x",
|
|
241
|
-
"canada",
|
|
242
|
-
"clustered-bar-2x",
|
|
243
|
-
"clustered-column",
|
|
244
|
-
"dot-plot",
|
|
245
|
-
"dot-plot-2x",
|
|
246
|
-
"dot-plot-3x",
|
|
247
|
-
"dot-plot-4x",
|
|
248
|
-
"dot-plot-5x",
|
|
249
|
-
"dot-plot-6x",
|
|
250
|
-
"dumbbell",
|
|
251
|
-
"line-2x",
|
|
252
|
-
"line-3x",
|
|
253
|
-
"line-with-high-low",
|
|
254
|
-
"line-with-high-low-and-markers",
|
|
255
|
-
"line-with-markers-2x",
|
|
256
|
-
"line-with-markers-3x",
|
|
257
|
-
"sparkline",
|
|
258
|
-
"sparkline-2x",
|
|
259
|
-
"sparkline-3x",
|
|
260
|
-
"sparkline-4x",
|
|
261
|
-
"sparkline-5x",
|
|
262
|
-
"sparkline-6x",
|
|
263
|
-
"stacked-area-2x",
|
|
264
|
-
"stacked-bar-2x",
|
|
265
|
-
"stacked-column-2x",
|
|
266
|
-
"stacked-line-2x",
|
|
267
|
-
"stacked-line-with-markers-2x",
|
|
268
|
-
"treemap-2x",
|
|
269
|
-
"treemap-3x",
|
|
270
|
-
"united-kingdom",
|
|
271
|
-
"united-states"
|
|
272
|
-
],
|
|
273
|
-
narratives: [
|
|
274
|
-
"problem-solution",
|
|
275
|
-
"scqa",
|
|
276
|
-
"pyramid-principle",
|
|
277
|
-
"situation-complication-resolution",
|
|
278
|
-
"what-so-what-now-what",
|
|
279
|
-
"strategic-narrative",
|
|
280
|
-
"golden-circle",
|
|
281
|
-
"conference-talk",
|
|
282
|
-
"transformation-arc",
|
|
283
|
-
"pitch-deck",
|
|
284
|
-
"early-startup-pitch",
|
|
285
|
-
"venture-pitch",
|
|
286
|
-
"persuasive-sales",
|
|
287
|
-
"sparkline",
|
|
288
|
-
"company-intro",
|
|
289
|
-
"marketing-strategy",
|
|
290
|
-
"product-launch",
|
|
291
|
-
"strategic-advisory",
|
|
292
|
-
"challenge-resolution",
|
|
293
|
-
"project-proposal",
|
|
294
|
-
"vision-roadmap",
|
|
295
|
-
"failure-analysis",
|
|
296
|
-
"star-method",
|
|
297
|
-
"classic-story",
|
|
298
|
-
"heros-journey",
|
|
299
|
-
"business-narrative",
|
|
300
|
-
"change-story",
|
|
301
|
-
"rags-to-riches",
|
|
302
|
-
"underdog-victory",
|
|
303
|
-
"survival-story",
|
|
304
|
-
"educate",
|
|
305
|
-
"persuade",
|
|
306
|
-
"reveal",
|
|
307
|
-
"justice",
|
|
308
|
-
"innovation",
|
|
309
|
-
"focus",
|
|
310
|
-
"qbr",
|
|
311
|
-
"business-review",
|
|
312
|
-
"board-meeting",
|
|
313
|
-
"weekly-progress",
|
|
314
|
-
"status-update",
|
|
315
|
-
"performance-review",
|
|
316
|
-
"survey-analysis",
|
|
317
|
-
"trend-analysis",
|
|
318
|
-
"data-story",
|
|
319
|
-
"employee-review",
|
|
320
|
-
"performance-improvement-plan",
|
|
321
|
-
"capacity-planning"
|
|
322
|
-
],
|
|
323
|
-
socialPlatforms: [
|
|
324
|
-
"linkedin",
|
|
325
|
-
"x",
|
|
326
|
-
"github",
|
|
327
|
-
"youtube",
|
|
328
|
-
"instagram",
|
|
329
|
-
"facebook",
|
|
330
|
-
"tiktok",
|
|
331
|
-
"threads",
|
|
332
|
-
"mastodon",
|
|
333
|
-
"bluesky"
|
|
334
|
-
],
|
|
335
|
-
languages: [
|
|
336
|
-
"afrikaans",
|
|
337
|
-
"albanian",
|
|
338
|
-
"amharic",
|
|
339
|
-
"arabic",
|
|
340
|
-
"armenian",
|
|
341
|
-
"aymara",
|
|
342
|
-
"azerbaijani",
|
|
343
|
-
"bengali",
|
|
344
|
-
"berber-latin",
|
|
345
|
-
"bosnian-latin",
|
|
346
|
-
"bulgarian",
|
|
347
|
-
"catalan",
|
|
348
|
-
"cebuano",
|
|
349
|
-
"chinese-simplified",
|
|
350
|
-
"chinese-traditional",
|
|
351
|
-
"chittagonian",
|
|
352
|
-
"croatian",
|
|
353
|
-
"czech",
|
|
354
|
-
"danish",
|
|
355
|
-
"dutch",
|
|
356
|
-
"english",
|
|
357
|
-
"english-au",
|
|
358
|
-
"english-ca",
|
|
359
|
-
"english-gb",
|
|
360
|
-
"english-in",
|
|
361
|
-
"english-us",
|
|
362
|
-
"estonian",
|
|
363
|
-
"filipino",
|
|
364
|
-
"finnish",
|
|
365
|
-
"french",
|
|
366
|
-
"fulfulde",
|
|
367
|
-
"galician",
|
|
368
|
-
"georgian",
|
|
369
|
-
"german",
|
|
370
|
-
"greek",
|
|
371
|
-
"gujarati",
|
|
372
|
-
"hausa",
|
|
373
|
-
"hebrew",
|
|
374
|
-
"hindi",
|
|
375
|
-
"hungarian",
|
|
376
|
-
"igbo",
|
|
377
|
-
"indonesian",
|
|
378
|
-
"italian",
|
|
379
|
-
"japanese",
|
|
380
|
-
"kannada",
|
|
381
|
-
"kazakh",
|
|
382
|
-
"khmer",
|
|
383
|
-
"kinyarwanda",
|
|
384
|
-
"korean",
|
|
385
|
-
"kurmanji",
|
|
386
|
-
"latvian",
|
|
387
|
-
"lithuanian",
|
|
388
|
-
"macedonian",
|
|
389
|
-
"malagasy",
|
|
390
|
-
"malay",
|
|
391
|
-
"malayalam",
|
|
392
|
-
"maori",
|
|
393
|
-
"marathi",
|
|
394
|
-
"mongolian",
|
|
395
|
-
"nepali",
|
|
396
|
-
"norwegian",
|
|
397
|
-
"odia",
|
|
398
|
-
"oromo",
|
|
399
|
-
"pashto",
|
|
400
|
-
"persian",
|
|
401
|
-
"polish",
|
|
402
|
-
"portuguese",
|
|
403
|
-
"punjabi-gurmukhi",
|
|
404
|
-
"punjabi-shahmukhi",
|
|
405
|
-
"romanian",
|
|
406
|
-
"russian",
|
|
407
|
-
"serbian-cyrillic",
|
|
408
|
-
"serbian-latin",
|
|
409
|
-
"shona",
|
|
410
|
-
"slovak",
|
|
411
|
-
"slovenian",
|
|
412
|
-
"somali",
|
|
413
|
-
"spanish",
|
|
414
|
-
"swahili",
|
|
415
|
-
"swedish",
|
|
416
|
-
"tagalog",
|
|
417
|
-
"tajik",
|
|
418
|
-
"tamil",
|
|
419
|
-
"telugu",
|
|
420
|
-
"thai",
|
|
421
|
-
"turkish",
|
|
422
|
-
"ukrainian",
|
|
423
|
-
"urdu",
|
|
424
|
-
"uzbek-latin",
|
|
425
|
-
"vietnamese-quoc-ngu",
|
|
426
|
-
"xhosa",
|
|
427
|
-
"yoruba",
|
|
428
|
-
"zulu"
|
|
429
|
-
],
|
|
430
|
-
colorSchemes: [
|
|
431
|
-
"black-and-white",
|
|
432
|
-
"bold-red",
|
|
433
|
-
"boost",
|
|
434
|
-
"burnt-orange",
|
|
435
|
-
"cool-horizon",
|
|
436
|
-
"corporate-blue",
|
|
437
|
-
"deep-purple",
|
|
438
|
-
"forest-green",
|
|
439
|
-
"golden-yellow",
|
|
440
|
-
"luxury",
|
|
441
|
-
"pastel-red",
|
|
442
|
-
"slate-gray",
|
|
443
|
-
"steel-blue",
|
|
444
|
-
"vibes"
|
|
445
|
-
],
|
|
446
|
-
fontSchemes: [
|
|
447
|
-
"consolas",
|
|
448
|
-
"courier-new",
|
|
449
|
-
"arial",
|
|
450
|
-
"calibri",
|
|
451
|
-
"impact",
|
|
452
|
-
"lucida-sans",
|
|
453
|
-
"segoe-ui",
|
|
454
|
-
"segoe-ui-light",
|
|
455
|
-
"tahoma",
|
|
456
|
-
"trebuchet-ms",
|
|
457
|
-
"verdana",
|
|
458
|
-
"bookman",
|
|
459
|
-
"century-schoolbook",
|
|
460
|
-
"constantia",
|
|
461
|
-
"garamond",
|
|
462
|
-
"rockwell",
|
|
463
|
-
"times-new-roman",
|
|
464
|
-
"aptos",
|
|
465
|
-
"grandview",
|
|
466
|
-
"seaford",
|
|
467
|
-
"skeena",
|
|
468
|
-
"tenorite",
|
|
469
|
-
"georgia",
|
|
470
|
-
"microsoft-yahei",
|
|
471
|
-
"simsun",
|
|
472
|
-
"fangsong",
|
|
473
|
-
"yu-gothic",
|
|
474
|
-
"pmingliu",
|
|
475
|
-
"mingliu",
|
|
476
|
-
"ms-mincho",
|
|
477
|
-
"malgun-gothic",
|
|
478
|
-
"batang",
|
|
479
|
-
"gungsuh",
|
|
480
|
-
"mangal",
|
|
481
|
-
"nirmala-ui",
|
|
482
|
-
"latha",
|
|
483
|
-
"david",
|
|
484
|
-
"miriam",
|
|
485
|
-
"gisha",
|
|
486
|
-
"vrinda",
|
|
487
|
-
"shruti",
|
|
488
|
-
"tunga",
|
|
489
|
-
"kartika",
|
|
490
|
-
"kalinga",
|
|
491
|
-
"raavi",
|
|
492
|
-
"gautami",
|
|
493
|
-
"arabic-typesetting",
|
|
494
|
-
"microsoft-jhenghei",
|
|
495
|
-
"meiryo",
|
|
496
|
-
"angsana-new",
|
|
497
|
-
"aparajita",
|
|
498
|
-
"dilleniaupc",
|
|
499
|
-
"sakkal-majalla",
|
|
500
|
-
"shonar-bangla",
|
|
501
|
-
"sylfaen",
|
|
502
|
-
"traditional-arabic",
|
|
503
|
-
"montserrat",
|
|
504
|
-
"open-sans",
|
|
505
|
-
"poppins",
|
|
506
|
-
"pt-serif",
|
|
507
|
-
"raleway",
|
|
508
|
-
"roboto",
|
|
509
|
-
"noto-sans-arabic",
|
|
510
|
-
"noto-sans-armenian",
|
|
511
|
-
"noto-sans-bengali",
|
|
512
|
-
"noto-sans-devangari",
|
|
513
|
-
"noto-sans-georgian",
|
|
514
|
-
"noto-sans-gujarati",
|
|
515
|
-
"noto-sans-gurmukhi",
|
|
516
|
-
"noto-sans-hebrew",
|
|
517
|
-
"noto-sans-jp",
|
|
518
|
-
"noto-sans-kannada",
|
|
519
|
-
"noto-sans-kr",
|
|
520
|
-
"noto-sans-malayalam",
|
|
521
|
-
"noto-sans-mongolian",
|
|
522
|
-
"noto-sans-oriya",
|
|
523
|
-
"noto-sans-sc",
|
|
524
|
-
"noto-sans-tamil",
|
|
525
|
-
"noto-sans-tc",
|
|
526
|
-
"noto-sans-telugu",
|
|
527
|
-
"noto-sans",
|
|
528
|
-
"noto-sans-thai",
|
|
529
|
-
"noto-nastaliq-urdu",
|
|
530
|
-
"noto-naksh-arabic",
|
|
531
|
-
"noto-sans-ethiopic",
|
|
532
|
-
"noto-sans-khmer",
|
|
533
|
-
"nyala",
|
|
534
|
-
"daunpenh",
|
|
535
|
-
"khmer-ui"
|
|
536
|
-
]
|
|
537
|
-
};
|
|
538
|
-
var deprecatedCatalogIds = {
|
|
539
|
-
"audiences/executives": "executive",
|
|
540
|
-
"audiences/investors": "investor",
|
|
541
|
-
"audiences/customers": "customer",
|
|
542
|
-
"audiences/sales-team": "sales",
|
|
543
|
-
"audiences/marketing-team": "marketing",
|
|
544
|
-
"audiences/regulators": "regulatory",
|
|
545
|
-
"chartTypes/100pct-bullet-bar": "100pct-stacked-bar-3x",
|
|
546
|
-
"chartTypes/100pct-bullet-bar-2x": "100pct-stacked-bar-3x",
|
|
547
|
-
"chartTypes/100pct-bullet-bar-3x": "100pct-stacked-bar-3x",
|
|
548
|
-
"chartTypes/100pct-bullet-column": "100pct-stacked-column-3x",
|
|
549
|
-
"chartTypes/100pct-bullet-column-2x": "100pct-stacked-column-3x",
|
|
550
|
-
"chartTypes/100pct-bullet-column-3x": "100pct-stacked-column-3x",
|
|
551
|
-
"chartTypes/100pct-progress-bar": "100pct-stacked-bar-3x",
|
|
552
|
-
"chartTypes/100pct-stacked-area-2x": "100pct-stacked-area-3x",
|
|
553
|
-
"chartTypes/100pct-stacked-bar-2x": "100pct-stacked-bar-3x",
|
|
554
|
-
"chartTypes/100pct-stacked-column-2x": "100pct-stacked-column-3x",
|
|
555
|
-
"chartTypes/australia": "world",
|
|
556
|
-
"chartTypes/box-and-whisker-2x": "box-and-whisker",
|
|
557
|
-
"chartTypes/box-and-whisker-3x": "box-and-whisker",
|
|
558
|
-
"chartTypes/bullet-bar": "bar",
|
|
559
|
-
"chartTypes/bullet-bar-2x": "bar",
|
|
560
|
-
"chartTypes/bullet-bar-3x": "bar",
|
|
561
|
-
"chartTypes/bullet-column": "column",
|
|
562
|
-
"chartTypes/bullet-column-2x": "column",
|
|
563
|
-
"chartTypes/bullet-column-3x": "column",
|
|
564
|
-
"chartTypes/canada": "world",
|
|
565
|
-
"chartTypes/clustered-bar-2x": "bar",
|
|
566
|
-
"chartTypes/clustered-column": "column",
|
|
567
|
-
"chartTypes/dot-plot": "scatter",
|
|
568
|
-
"chartTypes/dot-plot-2x": "scatter",
|
|
569
|
-
"chartTypes/dot-plot-3x": "scatter",
|
|
570
|
-
"chartTypes/dot-plot-4x": "scatter",
|
|
571
|
-
"chartTypes/dot-plot-5x": "scatter",
|
|
572
|
-
"chartTypes/dot-plot-6x": "scatter",
|
|
573
|
-
"chartTypes/dumbbell": "scatter",
|
|
574
|
-
"chartTypes/line-2x": "line",
|
|
575
|
-
"chartTypes/line-3x": "line",
|
|
576
|
-
"chartTypes/line-with-high-low": "line",
|
|
577
|
-
"chartTypes/line-with-high-low-and-markers": "line-with-markers",
|
|
578
|
-
"chartTypes/line-with-markers-2x": "line-with-markers",
|
|
579
|
-
"chartTypes/line-with-markers-3x": "line-with-markers",
|
|
580
|
-
"chartTypes/sparkline": "line",
|
|
581
|
-
"chartTypes/sparkline-2x": "line",
|
|
582
|
-
"chartTypes/sparkline-3x": "line",
|
|
583
|
-
"chartTypes/sparkline-4x": "line",
|
|
584
|
-
"chartTypes/sparkline-5x": "line",
|
|
585
|
-
"chartTypes/sparkline-6x": "line",
|
|
586
|
-
"chartTypes/stacked-area-2x": "stacked-area-3x",
|
|
587
|
-
"chartTypes/stacked-bar-2x": "stacked-bar-3x",
|
|
588
|
-
"chartTypes/stacked-column-2x": "stacked-column-3x",
|
|
589
|
-
"chartTypes/stacked-line-2x": "stacked-line-3x",
|
|
590
|
-
"chartTypes/stacked-line-with-markers-2x": "stacked-line-with-markers-3x",
|
|
591
|
-
"chartTypes/treemap-2x": "treemap",
|
|
592
|
-
"chartTypes/treemap-3x": "treemap",
|
|
593
|
-
"chartTypes/united-kingdom": "world",
|
|
594
|
-
"chartTypes/united-states": "world"
|
|
595
|
-
};
|
|
596
|
-
|
|
597
41
|
// src/chart-options.ts
|
|
598
42
|
var END_POSITIONS = ["center", "inside-end", "inside-base", "outside-end"];
|
|
599
43
|
var STACKED_POSITIONS = ["center", "inside-end", "inside-base"];
|
|
@@ -602,9 +46,12 @@ var PIE_POSITIONS = ["center", "inside-end", "outside-end"];
|
|
|
602
46
|
var NONE = [];
|
|
603
47
|
var VALUE_CATEGORY = ["category", "value"];
|
|
604
48
|
var ALL_CONTENT = ["category", "value", "percent"];
|
|
605
|
-
var
|
|
606
|
-
var
|
|
607
|
-
var
|
|
49
|
+
var COMBO_POSITIONS = ["center", "inside-end", "inside-base", "outside-end", "above", "below", "left", "right"];
|
|
50
|
+
var categoryKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "histogram", "pareto", "box", "waterfall", "funnel", "combo"]);
|
|
51
|
+
var valueKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "histogram", "pareto", "box", "waterfall", "combo"]);
|
|
52
|
+
var legendKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "pie", "doughnut", "scatter", "radar", "box", "combo"]);
|
|
53
|
+
var highlightSeriesKinds = /* @__PURE__ */ new Set(["bar", "line", "area", "scatter", "radar"]);
|
|
54
|
+
var highlightCategoryKinds = /* @__PURE__ */ new Set(["bar", "line", "pie", "doughnut"]);
|
|
608
55
|
function labelSupport(target) {
|
|
609
56
|
const none = { supported: true, content: VALUE_CATEGORY, positions: NONE, defaultPosition: null, defaultOn: false };
|
|
610
57
|
switch (target.kind) {
|
|
@@ -613,6 +60,9 @@ function labelSupport(target) {
|
|
|
613
60
|
case "line":
|
|
614
61
|
case "scatter":
|
|
615
62
|
return { ...none, positions: POINT_POSITIONS, defaultPosition: "above" };
|
|
63
|
+
// Columns take the clustered positions and lines the point positions ('center' fits both); each part falls back to its own default.
|
|
64
|
+
case "combo":
|
|
65
|
+
return { ...none, positions: COMBO_POSITIONS, defaultPosition: "outside-end" };
|
|
616
66
|
case "pie":
|
|
617
67
|
return { ...none, content: ALL_CONTENT, positions: PIE_POSITIONS, defaultPosition: "outside-end" };
|
|
618
68
|
case "doughnut":
|
|
@@ -634,25 +84,26 @@ function labelSupport(target) {
|
|
|
634
84
|
}
|
|
635
85
|
function chartOptionSupport(target) {
|
|
636
86
|
return {
|
|
637
|
-
axisTitles: { category: categoryKinds.has(target.kind), value: valueKinds.has(target.kind) },
|
|
87
|
+
axisTitles: { category: categoryKinds.has(target.kind), value: valueKinds.has(target.kind), secondary: target.kind === "combo" },
|
|
638
88
|
legend: legendKinds.has(target.kind),
|
|
89
|
+
highlight: { series: highlightSeriesKinds.has(target.kind), categories: highlightCategoryKinds.has(target.kind) },
|
|
639
90
|
dataLabels: labelSupport(target)
|
|
640
91
|
};
|
|
641
92
|
}
|
|
642
93
|
var KEPT = {
|
|
643
94
|
column: { kind: "bar" },
|
|
644
|
-
"stacked-column
|
|
645
|
-
"100pct-stacked-column
|
|
95
|
+
"stacked-column": { kind: "bar", stacked: true },
|
|
96
|
+
"100pct-stacked-column": { kind: "bar", stacked: true },
|
|
646
97
|
bar: { kind: "bar" },
|
|
647
|
-
"stacked-bar
|
|
648
|
-
"100pct-stacked-bar
|
|
98
|
+
"stacked-bar": { kind: "bar", stacked: true },
|
|
99
|
+
"100pct-stacked-bar": { kind: "bar", stacked: true },
|
|
649
100
|
line: { kind: "line" },
|
|
650
101
|
"line-with-markers": { kind: "line" },
|
|
651
|
-
"stacked-line
|
|
652
|
-
"stacked-line-with-markers
|
|
102
|
+
"stacked-line": { kind: "line", stacked: true },
|
|
103
|
+
"stacked-line-with-markers": { kind: "line", stacked: true },
|
|
653
104
|
area: { kind: "area" },
|
|
654
|
-
"stacked-area
|
|
655
|
-
"100pct-stacked-area
|
|
105
|
+
"stacked-area": { kind: "area", stacked: true },
|
|
106
|
+
"100pct-stacked-area": { kind: "area", stacked: true },
|
|
656
107
|
pie: { kind: "pie" },
|
|
657
108
|
doughnut: { kind: "doughnut" },
|
|
658
109
|
scatter: { kind: "scatter" },
|
|
@@ -665,14 +116,14 @@ var KEPT = {
|
|
|
665
116
|
"box-and-whisker": { kind: "box" },
|
|
666
117
|
waterfall: { kind: "waterfall" },
|
|
667
118
|
funnel: { kind: "funnel" },
|
|
668
|
-
world: { kind: "map" }
|
|
119
|
+
world: { kind: "map" },
|
|
120
|
+
combo: { kind: "combo" }
|
|
669
121
|
};
|
|
670
122
|
function chartOptionTarget(typeId) {
|
|
671
123
|
if (typeof typeId !== "string") return void 0;
|
|
672
124
|
const raw = typeId.trim().toLowerCase();
|
|
673
125
|
const id = raw === "donut" ? "doughnut" : raw;
|
|
674
|
-
const
|
|
675
|
-
const target = Object.hasOwn(KEPT, kept) ? KEPT[kept] : void 0;
|
|
126
|
+
const target = Object.hasOwn(KEPT, id) ? KEPT[id] : void 0;
|
|
676
127
|
return target ? { ...target } : void 0;
|
|
677
128
|
}
|
|
678
129
|
var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -686,11 +137,25 @@ function resolveChartOptions(chart, target) {
|
|
|
686
137
|
const support = target ? chartOptionSupport(target) : void 0;
|
|
687
138
|
const adapt = (option, reason, message) => result.diagnostics.push({ code: "chart-option-adapted", option, reason, message });
|
|
688
139
|
const kind2 = target?.kind ?? "unknown";
|
|
140
|
+
const combo = target?.kind === "combo";
|
|
141
|
+
if (!combo) {
|
|
142
|
+
for (const option of ["line", "secondaryAxis"]) {
|
|
143
|
+
if (chart[option] !== void 0) adapt(option, "unsupported-type", `Only a 'combo' chart draws line series${option === "secondaryAxis" ? " on a secondary axis" : ""}; ${option} is ignored on a '${kind2}' chart.`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
689
146
|
if (record2(chart.axisTitles)) {
|
|
690
|
-
for (const axis of ["category", "value"]) {
|
|
147
|
+
for (const axis of ["category", "value", "secondary"]) {
|
|
691
148
|
const raw = chart.axisTitles[axis];
|
|
692
149
|
if (typeof raw !== "string" || !raw.trim()) continue;
|
|
693
|
-
if (support && !support.axisTitles
|
|
150
|
+
if (axis === "secondary" && support && !support.axisTitles.secondary) {
|
|
151
|
+
adapt("axisTitles.secondary", "unsupported-type", `Only a 'combo' chart has a secondary value axis; the secondary axis title is not drawn or exported on a '${kind2}' chart.`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (axis === "secondary" && combo && !(Array.isArray(chart.secondaryAxis) && chart.secondaryAxis.some((name) => typeof name === "string"))) {
|
|
155
|
+
adapt("axisTitles.secondary", "unsupported-type", "This combo chart plots no series on a secondary axis (secondaryAxis is absent); the secondary axis title is not drawn or exported.");
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (axis !== "secondary" && support && !support.axisTitles[axis]) {
|
|
694
159
|
adapt(`axisTitles.${axis}`, "unsupported-type", `A '${kind2}' chart has no ${axis} axis to title; the ${axis} axis title is not drawn or exported.`);
|
|
695
160
|
continue;
|
|
696
161
|
}
|
|
@@ -717,8 +182,18 @@ function resolveChartOptions(chart, target) {
|
|
|
717
182
|
if (!content.length) content.push("value");
|
|
718
183
|
const positions = support?.dataLabels.positions ?? NONE;
|
|
719
184
|
let position = support?.dataLabels.defaultPosition ?? null;
|
|
720
|
-
|
|
721
|
-
|
|
185
|
+
let linePosition;
|
|
186
|
+
const requestedPosition = typeof options.position === "string" && POSITIONS.has(options.position) && options.position !== "auto" ? options.position : void 0;
|
|
187
|
+
if (combo) {
|
|
188
|
+
linePosition = "above";
|
|
189
|
+
if (requestedPosition) {
|
|
190
|
+
if (END_POSITIONS.includes(requestedPosition)) position = requestedPosition;
|
|
191
|
+
else adapt("dataLabels.position", "unsupported-position", `The column series of a combo chart cannot place data labels '${requestedPosition}'; they use outside-end.`);
|
|
192
|
+
if (POINT_POSITIONS.includes(requestedPosition)) linePosition = requestedPosition;
|
|
193
|
+
else adapt("dataLabels.position", "unsupported-position", `The line series of a combo chart cannot place data labels '${requestedPosition}'; they use above.`);
|
|
194
|
+
}
|
|
195
|
+
} else if (requestedPosition) {
|
|
196
|
+
if (!support || positions.includes(requestedPosition)) position = requestedPosition;
|
|
722
197
|
else adapt("dataLabels.position", "unsupported-position", `A '${kind2}'${target?.stacked ? " stacked" : ""} chart cannot place data labels '${options.position}'; the type's default position is used.`);
|
|
723
198
|
}
|
|
724
199
|
let separator = typeof options.separator === "string" ? options.separator : DEFAULT_CHART_LABEL_SEPARATOR;
|
|
@@ -726,10 +201,23 @@ function resolveChartOptions(chart, target) {
|
|
|
726
201
|
separator = separator.replace(/[\r\n]+/g, " ");
|
|
727
202
|
adapt("dataLabels.separator", "unsupported-content", "A data label is one line; the line break in the separator is replaced with a space.");
|
|
728
203
|
}
|
|
729
|
-
result.dataLabels = { content, position, separator };
|
|
204
|
+
result.dataLabels = { content, position, separator, ...linePosition ? { linePosition } : {} };
|
|
730
205
|
}
|
|
731
206
|
}
|
|
732
|
-
|
|
207
|
+
if (record2(chart.highlight)) {
|
|
208
|
+
const names = (value) => Array.isArray(value) ? [...new Set(value.filter((entry) => typeof entry === "string"))] : [];
|
|
209
|
+
const kept = { series: [], categories: [] };
|
|
210
|
+
for (const part of ["series", "categories"]) {
|
|
211
|
+
const requested = names(chart.highlight[part]);
|
|
212
|
+
if (!requested.length) continue;
|
|
213
|
+
if (support && !support.highlight[part]) {
|
|
214
|
+
const alternative = part === "series" ? support.highlight.categories ? " (name categories instead)" : "" : support.highlight.series ? " (name series instead)" : "";
|
|
215
|
+
adapt(`highlight.${part}`, "unsupported-type", `A '${kind2}' chart cannot highlight ${part}${alternative}; the highlighted ${part} are ignored.`);
|
|
216
|
+
} else kept[part] = requested;
|
|
217
|
+
}
|
|
218
|
+
if (kept.series.length || kept.categories.length) result.highlight = kept;
|
|
219
|
+
}
|
|
220
|
+
result.active = result.legend !== void 0 || result.dataLabels !== void 0 || result.dataLabelsOff === true || result.axisTitles.category !== void 0 || result.axisTitles.value !== void 0 || result.axisTitles.secondary !== void 0;
|
|
733
221
|
return result;
|
|
734
222
|
}
|
|
735
223
|
function formatChartLabelNumber(value) {
|
|
@@ -741,6 +229,14 @@ function formatChartLabelPercent(share) {
|
|
|
741
229
|
function chartLabelText(parts, content, separator = DEFAULT_CHART_LABEL_SEPARATOR) {
|
|
742
230
|
return CONTENT_ORDER.filter((part) => content.includes(part) && parts[part] !== void 0).map((part) => parts[part]).join(separator);
|
|
743
231
|
}
|
|
232
|
+
function chartHighlightMarks(highlight, data) {
|
|
233
|
+
if (!highlight) return void 0;
|
|
234
|
+
const first = data.columns.length > 1 ? data.hasX ? 2 : 1 : 0;
|
|
235
|
+
const series = data.columns.slice(first).map((name) => highlight.series.includes(name));
|
|
236
|
+
const label = (cell) => cell === null || cell === void 0 ? "" : String(cell);
|
|
237
|
+
const categories = data.columns.length > 1 ? data.rows.map((row) => highlight.categories.includes(label(row[0]))) : data.rows.map(() => false);
|
|
238
|
+
return series.some(Boolean) || categories.some(Boolean) ? { series, categories } : void 0;
|
|
239
|
+
}
|
|
744
240
|
|
|
745
241
|
// src/content-walk.ts
|
|
746
242
|
function isRecord(value) {
|
|
@@ -928,6 +424,24 @@ function formatSlideNumber(format, current, total) {
|
|
|
928
424
|
return { text: text2, fields: fields2 };
|
|
929
425
|
}
|
|
930
426
|
|
|
427
|
+
// src/deck-metadata.ts
|
|
428
|
+
function recordsOf(value) {
|
|
429
|
+
return (Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value]).filter(isRecord);
|
|
430
|
+
}
|
|
431
|
+
function speakersOf(presentation) {
|
|
432
|
+
return isRecord(presentation) ? recordsOf(presentation.speaker) : [];
|
|
433
|
+
}
|
|
434
|
+
function organizationsOf(presentation) {
|
|
435
|
+
return isRecord(presentation) ? recordsOf(presentation.organization) : [];
|
|
436
|
+
}
|
|
437
|
+
function primarySpeaker(presentation) {
|
|
438
|
+
return speakersOf(presentation)[0];
|
|
439
|
+
}
|
|
440
|
+
function primaryOrganization(presentation) {
|
|
441
|
+
const organizations = organizationsOf(presentation);
|
|
442
|
+
return organizations.find((item) => item.role === "primary") ?? organizations[0];
|
|
443
|
+
}
|
|
444
|
+
|
|
931
445
|
// src/variables.ts
|
|
932
446
|
var VARIABLE_KINDS = ["color", "text", "number", "date", "image", "url", "list"];
|
|
933
447
|
var DEFAULT_VARIABLE_DATE_FORMAT = "MMMM d, yyyy";
|
|
@@ -941,12 +455,15 @@ var OPFVariableError = class extends Error {
|
|
|
941
455
|
}
|
|
942
456
|
};
|
|
943
457
|
var idPattern = /^[a-z][a-z0-9-]*$/;
|
|
944
|
-
var
|
|
458
|
+
var nameSource = String.raw`[a-z][a-z0-9-]*|(?:deck|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2}`;
|
|
459
|
+
var referencePattern = new RegExp(String.raw`^var:(${nameSource})$`);
|
|
460
|
+
var builtinNamePattern = /^(?:speakers|(?:deck|speaker|organization)(?:\.[A-Za-z0-9_-]+){1,2})$/;
|
|
461
|
+
var builtinUsePattern = /\{\{\s*(?:speakers\b|(?:deck|speaker|organization)\.)|^var:(?:speakers$|(?:deck|speaker|organization)\.)/;
|
|
945
462
|
var hexPattern = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
946
463
|
var urlPattern = /^(?:https?:\/\/|mailto:|tel:)\S+$/;
|
|
947
464
|
var datePrefixPattern = /^(\d{4}-\d{2}-\d{2})(?:[T ].*)?$/;
|
|
948
465
|
var decimalPattern = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
949
|
-
var tokenPattern =
|
|
466
|
+
var tokenPattern = new RegExp(String.raw`\\\{\{|\{\{\s*(${nameSource})\s*(?:\|([^{}]*))?\}\}`, "g");
|
|
950
467
|
var SAMPLES = {
|
|
951
468
|
color: "#000000",
|
|
952
469
|
text: "Sample text",
|
|
@@ -1039,8 +556,18 @@ function variableDeclarations(presentation) {
|
|
|
1039
556
|
}
|
|
1040
557
|
return out;
|
|
1041
558
|
}
|
|
559
|
+
function usesBuiltins(value, root = true) {
|
|
560
|
+
if (typeof value === "string") return value.length >= 6 && builtinUsePattern.test(value);
|
|
561
|
+
if (Array.isArray(value)) return value.some((entry) => usesBuiltins(entry, false));
|
|
562
|
+
if (!isRecord(value)) return false;
|
|
563
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
564
|
+
if (skippedKeys.has(key) || root && skippedRootKeys.has(key)) continue;
|
|
565
|
+
if (usesBuiltins(entry, false)) return true;
|
|
566
|
+
}
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
1042
569
|
function hasContentVariables(presentation) {
|
|
1043
|
-
return isTemplate(presentation) || variableDeclarations(presentation).some((declaration) => declaration.kind !== "color");
|
|
570
|
+
return isTemplate(presentation) || variableDeclarations(presentation).some((declaration) => declaration.kind !== "color") || usesBuiltins(presentation);
|
|
1044
571
|
}
|
|
1045
572
|
var POSITIVE_ZERO = "0";
|
|
1046
573
|
function formatVariableNumber(value, pattern) {
|
|
@@ -1127,6 +654,93 @@ function inlineText(effective, format, path, context) {
|
|
|
1127
654
|
return value.join(format ?? ", ");
|
|
1128
655
|
}
|
|
1129
656
|
}
|
|
657
|
+
var DECK_FIELDS = { name: "text", description: "text", author: "text" };
|
|
658
|
+
var SPEAKER_FIELDS = { name: "text", title: "text", email: "text", phone: "text", bio: "text", photo: "image" };
|
|
659
|
+
var ORGANIZATION_FIELDS = { name: "text", legalName: "text", tagline: "text", domain: "text", email: "text", phone: "text", logo: "image" };
|
|
660
|
+
function isBuiltinName(name) {
|
|
661
|
+
return builtinNamePattern.test(name);
|
|
662
|
+
}
|
|
663
|
+
function builtinFields(root) {
|
|
664
|
+
return root === "deck" ? DECK_FIELDS : root === "speaker" ? SPEAKER_FIELDS : ORGANIZATION_FIELDS;
|
|
665
|
+
}
|
|
666
|
+
function present(value) {
|
|
667
|
+
if (typeof value === "string") return value.trim() === "" ? void 0 : value;
|
|
668
|
+
if (isRecord(value)) return typeof value.src === "string" && value.src.trim() ? value : void 0;
|
|
669
|
+
return void 0;
|
|
670
|
+
}
|
|
671
|
+
function builtinSource(name, doc) {
|
|
672
|
+
if (name === "speakers") {
|
|
673
|
+
const names = speakersOf(doc).map((speaker) => present(speaker.name)).filter((entry) => typeof entry === "string");
|
|
674
|
+
return { ok: true, kind: "list", raw: names.length ? names : void 0 };
|
|
675
|
+
}
|
|
676
|
+
const parts = name.split(".");
|
|
677
|
+
const root = parts[0];
|
|
678
|
+
const fields2 = builtinFields(root);
|
|
679
|
+
const list = (names) => names.map((entry) => `'${entry}'`).join(", ");
|
|
680
|
+
if (root === "deck") {
|
|
681
|
+
const field2 = parts[1];
|
|
682
|
+
if (parts.length !== 2 || !Object.hasOwn(fields2, field2)) return { ok: false, message: `'${name}' is not a built-in variable; the deck built-ins are ${list(Object.keys(fields2).map((key) => `deck.${key}`))}.` };
|
|
683
|
+
const value = doc[field2];
|
|
684
|
+
return { ok: true, kind: "text", raw: field2 === "author" && Array.isArray(value) ? present(value.filter((entry) => typeof entry === "string").join(", ")) : present(value) };
|
|
685
|
+
}
|
|
686
|
+
const field = parts[parts.length - 1];
|
|
687
|
+
if (!Object.hasOwn(fields2, field)) {
|
|
688
|
+
return { ok: false, message: `'${name}' is not a built-in variable: '${field}' is not a ${root} field; the fields are ${list(Object.keys(fields2))}.` };
|
|
689
|
+
}
|
|
690
|
+
let entity;
|
|
691
|
+
if (parts.length === 2) entity = root === "speaker" ? primarySpeaker(doc) : primaryOrganization(doc);
|
|
692
|
+
else {
|
|
693
|
+
const id = parts[1];
|
|
694
|
+
const entries = root === "speaker" ? speakersOf(doc) : organizationsOf(doc);
|
|
695
|
+
entity = entries.find((entry) => entry.id === id);
|
|
696
|
+
if (!entity) return { ok: false, message: `'${name}' names no ${root} with id '${id}'.` };
|
|
697
|
+
}
|
|
698
|
+
return { ok: true, kind: fields2[field], raw: present(entity?.[field]) };
|
|
699
|
+
}
|
|
700
|
+
function builtinEffective(name, path, context) {
|
|
701
|
+
if (context.resolvingBuiltins.has(name)) return void 0;
|
|
702
|
+
const cached = context.builtins.get(name);
|
|
703
|
+
if (cached !== void 0) {
|
|
704
|
+
if (cached === null) diag(context, unknownBuiltin(name, path, context), `ubi:${name}:${path}`);
|
|
705
|
+
else if (cached.status === "unfilled") diag(context, missingBuiltin(name, path), `bim:${name}:${path}`);
|
|
706
|
+
return cached ?? void 0;
|
|
707
|
+
}
|
|
708
|
+
const source = builtinSource(name, context.doc);
|
|
709
|
+
if (!source.ok) {
|
|
710
|
+
context.builtins.set(name, null);
|
|
711
|
+
diag(context, unknownBuiltin(name, path, context), `ubi:${name}:${path}`);
|
|
712
|
+
return void 0;
|
|
713
|
+
}
|
|
714
|
+
const declaration = { id: name, kind: source.kind, path: "", required: context.keepMissingBuiltins };
|
|
715
|
+
let effective;
|
|
716
|
+
const coerced = source.raw === void 0 ? void 0 : coerceVariableValue(source.kind, source.raw);
|
|
717
|
+
if (coerced?.ok) {
|
|
718
|
+
let value = coerced.value;
|
|
719
|
+
if (typeof value === "string" && value.includes("{{")) {
|
|
720
|
+
context.resolvingBuiltins.add(name);
|
|
721
|
+
value = interpolate(value, path, context).value;
|
|
722
|
+
context.resolvingBuiltins.delete(name);
|
|
723
|
+
}
|
|
724
|
+
effective = { declaration: { ...declaration, value }, status: "filled", value, provided: false };
|
|
725
|
+
} else {
|
|
726
|
+
effective = { declaration, status: "unfilled", provided: false };
|
|
727
|
+
diag(context, missingBuiltin(name, path), `bim:${name}:${path}`);
|
|
728
|
+
}
|
|
729
|
+
context.builtins.set(name, effective);
|
|
730
|
+
return effective;
|
|
731
|
+
}
|
|
732
|
+
function unknownBuiltin(name, path, context) {
|
|
733
|
+
const source = builtinSource(name, context.doc);
|
|
734
|
+
return { code: "variable-unknown-builtin", severity: "error", path, id: name, message: source.ok ? `'${name}' is not a built-in variable.` : source.message };
|
|
735
|
+
}
|
|
736
|
+
function missingBuiltin(name, path) {
|
|
737
|
+
return { code: "variable-builtin-missing", severity: "warning", path, id: name, message: `Built-in '${name}' has no value in this document, so it resolves to nothing; add the field it reads (see docs/templates-and-variables.md).` };
|
|
738
|
+
}
|
|
739
|
+
function lookupVariable(id, path, context) {
|
|
740
|
+
const declared = context.effective.get(id);
|
|
741
|
+
if (declared || !isBuiltinName(id)) return declared;
|
|
742
|
+
return builtinEffective(id, path, context);
|
|
743
|
+
}
|
|
1130
744
|
function interpolate(text2, path, context) {
|
|
1131
745
|
let changed = false;
|
|
1132
746
|
const value = text2.replace(tokenPattern, (match, id, format) => {
|
|
@@ -1138,9 +752,9 @@ function interpolate(text2, path, context) {
|
|
|
1138
752
|
return match;
|
|
1139
753
|
}
|
|
1140
754
|
context.uses.push({ id, path, form: "token" });
|
|
1141
|
-
const effective =
|
|
755
|
+
const effective = lookupVariable(id, path, context);
|
|
1142
756
|
if (!effective) {
|
|
1143
|
-
diag(context, { code: "variable-unknown", severity: "warning", path, id, message: `'{{${id}}}' names no declared variable; declare '${id}' in the top-level variables map, or write '\\{{' for literal braces.` }, `unk:${id}:${path}`);
|
|
757
|
+
if (!isBuiltinName(id)) diag(context, { code: "variable-unknown", severity: "warning", path, id, message: `'{{${id}}}' names no declared variable; declare '${id}' in the top-level variables map, or write '\\{{' for literal braces.` }, `unk:${id}:${path}`);
|
|
1144
758
|
return match;
|
|
1145
759
|
}
|
|
1146
760
|
if (effective.status === "unfilled" && !context.shape) {
|
|
@@ -1168,7 +782,7 @@ function reduceString(text2, path, parentIsArray, context) {
|
|
|
1168
782
|
const reference = referencePattern.exec(text2);
|
|
1169
783
|
if (reference) {
|
|
1170
784
|
const id = reference[1];
|
|
1171
|
-
const effective =
|
|
785
|
+
const effective = lookupVariable(id, path, context);
|
|
1172
786
|
if (effective && effective.declaration.kind !== "color") {
|
|
1173
787
|
context.uses.push({ id, path, form: "reference" });
|
|
1174
788
|
if (effective.status === "unfilled" && !context.shape) {
|
|
@@ -1250,7 +864,11 @@ function plan(presentation, values, options) {
|
|
|
1250
864
|
unescape: false,
|
|
1251
865
|
shape: options.shape === true,
|
|
1252
866
|
content: hasContentVariables(presentation) || template,
|
|
1253
|
-
seen: /* @__PURE__ */ new Set()
|
|
867
|
+
seen: /* @__PURE__ */ new Set(),
|
|
868
|
+
doc: presentation,
|
|
869
|
+
keepMissingBuiltins: options.examples === true,
|
|
870
|
+
builtins: /* @__PURE__ */ new Map(),
|
|
871
|
+
resolvingBuiltins: /* @__PURE__ */ new Set()
|
|
1254
872
|
};
|
|
1255
873
|
const unfilled = [];
|
|
1256
874
|
const examplesUsed = [];
|
|
@@ -1374,6 +992,32 @@ function listVariables(presentation, values = {}) {
|
|
|
1374
992
|
};
|
|
1375
993
|
});
|
|
1376
994
|
}
|
|
995
|
+
var FIELD_LABELS = { name: "name", legalName: "legal name", tagline: "tagline", domain: "domain", email: "email", phone: "phone", logo: "logo", title: "title", bio: "bio", photo: "photo", description: "description", author: "author" };
|
|
996
|
+
function listBuiltinVariables(presentation) {
|
|
997
|
+
if (!isRecord(presentation)) return [];
|
|
998
|
+
const names = [];
|
|
999
|
+
for (const field of Object.keys(DECK_FIELDS)) names.push({ name: `deck.${field}`, label: `Deck ${FIELD_LABELS[field]}` });
|
|
1000
|
+
for (const field of Object.keys(SPEAKER_FIELDS)) names.push({ name: `speaker.${field}`, label: `Speaker ${FIELD_LABELS[field]}` });
|
|
1001
|
+
names.push({ name: "speakers", label: "All speaker names" });
|
|
1002
|
+
for (const field of Object.keys(ORGANIZATION_FIELDS)) names.push({ name: `organization.${field}`, label: `Organization ${FIELD_LABELS[field]}` });
|
|
1003
|
+
for (const [root, entries] of [["speaker", speakersOf(presentation)], ["organization", organizationsOf(presentation)]]) {
|
|
1004
|
+
for (const entry of entries) {
|
|
1005
|
+
if (typeof entry.id !== "string" || entry.id === "") continue;
|
|
1006
|
+
for (const field of Object.keys(builtinFields(root))) names.push({ name: `${root}.${entry.id}.${field}`, label: `${root === "speaker" ? "Speaker" : "Organization"} ${entry.id} ${FIELD_LABELS[field]}` });
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
const built = plan(presentation, {}, { examples: false, partial: true, shape: true });
|
|
1010
|
+
built.context.content = true;
|
|
1011
|
+
walk(presentation, "", false, built.context);
|
|
1012
|
+
const out = [];
|
|
1013
|
+
for (const { name, label } of names) {
|
|
1014
|
+
const source = builtinSource(name, presentation);
|
|
1015
|
+
if (!source.ok) continue;
|
|
1016
|
+
const coerced = source.raw === void 0 ? void 0 : coerceVariableValue(source.kind, source.raw);
|
|
1017
|
+
out.push({ name, kind: source.kind, label, ...coerced?.ok ? { value: coerced.value } : {}, available: coerced?.ok === true, uses: built.context.uses.filter((use) => use.id === name) });
|
|
1018
|
+
}
|
|
1019
|
+
return out;
|
|
1020
|
+
}
|
|
1377
1021
|
|
|
1378
1022
|
// src/chart-data.ts
|
|
1379
1023
|
var record3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1451,7 +1095,7 @@ function excelInteger(integer) {
|
|
|
1451
1095
|
const placeholders = "#".repeat(width - zeros) + "0".repeat(zeros);
|
|
1452
1096
|
return placeholders.replace(/\B(?=(.{3})+$)/g, ",");
|
|
1453
1097
|
}
|
|
1454
|
-
function
|
|
1098
|
+
function toExcelNumberFormat(format) {
|
|
1455
1099
|
if (format === void 0 || format === "") return "General";
|
|
1456
1100
|
const parts = formatParts(format);
|
|
1457
1101
|
if (!parts) return "General";
|
|
@@ -1489,7 +1133,7 @@ function excelTokens(code) {
|
|
|
1489
1133
|
}
|
|
1490
1134
|
return tokens;
|
|
1491
1135
|
}
|
|
1492
|
-
function
|
|
1136
|
+
function fromExcelNumberFormat(code) {
|
|
1493
1137
|
if (typeof code !== "string") return void 0;
|
|
1494
1138
|
const trimmed = code.trim();
|
|
1495
1139
|
if (trimmed === "" || /^general$/i.test(trimmed)) return void 0;
|
|
@@ -1580,8 +1224,8 @@ function inlinedData(ref, datasets) {
|
|
|
1580
1224
|
const diagnostics = [];
|
|
1581
1225
|
const selection = selectFields(dataset.columns, ref.fields, "", "", diagnostics);
|
|
1582
1226
|
if (diagnostics.some((entry) => entry.code === "dataset-field-unknown")) return void 0;
|
|
1583
|
-
const
|
|
1584
|
-
return { columns: selection.columns.map(inlineColumn), rows:
|
|
1227
|
+
const rows3 = dataset.rows.map((row) => selection.indices.map((index) => Array.isArray(row) && index < row.length ? structuredClone(row[index]) : null));
|
|
1228
|
+
return { columns: selection.columns.map(inlineColumn), rows: rows3, ...record3(dataset.source) ? { source: structuredClone(dataset.source) } : {} };
|
|
1585
1229
|
}
|
|
1586
1230
|
function inlineDatasets(document) {
|
|
1587
1231
|
if (!record3(document)) return document;
|
|
@@ -1655,7 +1299,7 @@ function resolveChartData(chart, document, options = {}) {
|
|
|
1655
1299
|
const data = record3(chart) ? chart.data : void 0;
|
|
1656
1300
|
if (!record3(data)) return fail("no-columns", "The chart has no data.");
|
|
1657
1301
|
let columns2;
|
|
1658
|
-
let
|
|
1302
|
+
let rows3;
|
|
1659
1303
|
let columnsPath;
|
|
1660
1304
|
let rowsPath;
|
|
1661
1305
|
let source;
|
|
@@ -1675,15 +1319,12 @@ function resolveChartData(chart, document, options = {}) {
|
|
|
1675
1319
|
const selection = selectFields(dataset.columns, data.fields, at(base, "data", "fields"), columnsPath, diagnostics);
|
|
1676
1320
|
columns2 = selection.columns;
|
|
1677
1321
|
selected = selection.indices;
|
|
1678
|
-
|
|
1322
|
+
rows3 = dataset.rows;
|
|
1679
1323
|
if (record3(dataset.source)) source = dataset.source;
|
|
1680
|
-
} else if (typeof data.src === "string") {
|
|
1681
|
-
diagnostics.push({ code: "chart-data-source-unresolved", severity: "warning", path: at(base, "data", "src"), message: `chart data source '${data.src}' is not loaded by any engine; the preview and export draw a placeholder. Import the data inline (columns and rows, with a 'source' for provenance) or reference a dataset` });
|
|
1682
|
-
return fail("data-not-inline", "The chart reads an external data source, which no engine resolves.");
|
|
1683
1324
|
} else {
|
|
1684
1325
|
if (!Array.isArray(data.columns)) return fail("no-columns", "The chart data has no columns.");
|
|
1685
1326
|
columns2 = data.columns;
|
|
1686
|
-
|
|
1327
|
+
rows3 = Array.isArray(data.rows) ? data.rows : [];
|
|
1687
1328
|
columnsPath = at(base, "data", "columns");
|
|
1688
1329
|
rowsPath = at(base, "data", "rows");
|
|
1689
1330
|
formatDiagnostics(columns2, columnsPath, diagnostics);
|
|
@@ -1741,10 +1382,46 @@ function resolveChartData(chart, document, options = {}) {
|
|
|
1741
1382
|
series = [x];
|
|
1742
1383
|
x = void 0;
|
|
1743
1384
|
}
|
|
1385
|
+
let combo;
|
|
1386
|
+
if (record3(chart) && chartOptionTarget(chart.type)?.kind === "combo") {
|
|
1387
|
+
const listed = (option, problem) => {
|
|
1388
|
+
const found = /* @__PURE__ */ new Set();
|
|
1389
|
+
const value = chart[option];
|
|
1390
|
+
if (!Array.isArray(value)) return found;
|
|
1391
|
+
value.forEach((name, index) => {
|
|
1392
|
+
const path = at(base, option, index);
|
|
1393
|
+
const column = known(name, path);
|
|
1394
|
+
if (column === void 0) return;
|
|
1395
|
+
const reason = problem(column);
|
|
1396
|
+
if (reason) diagnostics.push({ code: "chart-mapping-adapted", severity: "warning", path, message: `${JSON.stringify(name)} ${reason}` });
|
|
1397
|
+
else found.add(column);
|
|
1398
|
+
});
|
|
1399
|
+
return found;
|
|
1400
|
+
};
|
|
1401
|
+
const notPlotted = "is not a plotted series of the chart";
|
|
1402
|
+
const lines = listed("line", (column) => series.includes(column) ? void 0 : `${notPlotted}; it is not drawn as a line`);
|
|
1403
|
+
if (chart.line === void 0 && series.length >= 2) lines.add(series[series.length - 1]);
|
|
1404
|
+
if (series.length && series.every((column) => lines.has(column))) {
|
|
1405
|
+
lines.delete(series[0]);
|
|
1406
|
+
diagnostics.push({ code: "chart-mapping-adapted", severity: "warning", path: at(base, chart.line === void 0 ? "type" : "line"), message: series.length === 1 ? `a combo chart needs at least two series, one drawn as columns and one as a line; its one series ${JSON.stringify(names[series[0]])} is drawn as columns` : `a combo chart keeps at least one column series; ${JSON.stringify(names[series[0]])} is drawn as columns, not as a line` });
|
|
1407
|
+
} else if (series.length === 1) {
|
|
1408
|
+
diagnostics.push({ code: "chart-mapping-adapted", severity: "warning", path: at(base, "type"), message: `a combo chart needs at least two series, one drawn as columns and one as a line; its one series ${JSON.stringify(names[series[0]])} is drawn as columns` });
|
|
1409
|
+
}
|
|
1410
|
+
const secondary = listed("secondaryAxis", (column) => !series.includes(column) ? `${notPlotted}; it has no axis to move to` : !lines.has(column) ? "is drawn as columns; only a line series can use the secondary axis, so it stays on the primary axis" : void 0);
|
|
1411
|
+
const bars = series.filter((column) => !lines.has(column));
|
|
1412
|
+
const primaryLines = series.filter((column) => lines.has(column) && !secondary.has(column));
|
|
1413
|
+
const secondaryLines = series.filter((column) => lines.has(column) && secondary.has(column));
|
|
1414
|
+
series = [...bars, ...primaryLines, ...secondaryLines];
|
|
1415
|
+
combo = [
|
|
1416
|
+
...bars.map(() => ({ role: "bar", axis: "primary" })),
|
|
1417
|
+
...primaryLines.map(() => ({ role: "line", axis: "primary" })),
|
|
1418
|
+
...secondaryLines.map(() => ({ role: "line", axis: "secondary" }))
|
|
1419
|
+
];
|
|
1420
|
+
}
|
|
1744
1421
|
const order = [category, ...x === void 0 ? [] : [x], ...series];
|
|
1745
|
-
if (!
|
|
1422
|
+
if (!rows3.length) return fail("no-rows", "The chart data has no rows.");
|
|
1746
1423
|
const lone = names.length === 1 && !diagnostics.some((entry) => entry.code === "dataset-field-unknown");
|
|
1747
|
-
const out =
|
|
1424
|
+
const out = rows3.map((row, rowIndex) => order.map((column, position) => {
|
|
1748
1425
|
const sourceIndex = selected ? selected[column] : column;
|
|
1749
1426
|
const cell = Array.isArray(row) && sourceIndex < row.length ? row[sourceIndex] : null;
|
|
1750
1427
|
if (position === 0 && !lone) return cell === void 0 ? null : cell;
|
|
@@ -1754,6 +1431,26 @@ function resolveChartData(chart, document, options = {}) {
|
|
|
1754
1431
|
}
|
|
1755
1432
|
return number;
|
|
1756
1433
|
}));
|
|
1434
|
+
const highlight = record3(chart) && record3(chart.highlight) ? chart.highlight : void 0;
|
|
1435
|
+
if (highlight) {
|
|
1436
|
+
const plotted = order.slice(order.length - series.length).map((index) => names[index]);
|
|
1437
|
+
const labels = lone ? void 0 : new Set(out.map((row) => row[0] === null || row[0] === void 0 ? "" : String(row[0])));
|
|
1438
|
+
const listed = (value) => Array.isArray(value) ? value : [];
|
|
1439
|
+
const highlightPath = at(base, "highlight");
|
|
1440
|
+
listed(highlight.series).forEach((name, index) => {
|
|
1441
|
+
const path = at(highlightPath, "series", index);
|
|
1442
|
+
if (typeof name !== "string" || !names.includes(name)) {
|
|
1443
|
+
diagnostics.push({ code: "chart-highlight-unknown-name", severity: "error", path, message: `highlight names series ${JSON.stringify(name)}, which the chart data does not have as a column; use one of ${names.map((entry) => JSON.stringify(entry)).join(", ")}` });
|
|
1444
|
+
} else if (!plotted.includes(name)) {
|
|
1445
|
+
diagnostics.push({ code: "chart-highlight-adapted", severity: "warning", path, message: `highlight names column ${JSON.stringify(name)}, which is not plotted as a series (it is the category or X column, or the mapping leaves it out); it highlights nothing` });
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
listed(highlight.categories).forEach((name, index) => {
|
|
1449
|
+
if (typeof name === "string" && labels?.has(name)) return;
|
|
1450
|
+
const shown = labels ? [...labels].slice(0, 12).map((entry) => JSON.stringify(entry)).join(", ") : "";
|
|
1451
|
+
diagnostics.push({ code: "chart-highlight-unknown-name", severity: "error", path: at(highlightPath, "categories", index), message: `highlight names category ${JSON.stringify(name)}, which no row of the chart data has as its label${shown ? `; the labels are ${shown}${labels.size > 12 ? ", ..." : ""}` : ""}` });
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1757
1454
|
return {
|
|
1758
1455
|
ok: true,
|
|
1759
1456
|
columns: order.map((index) => names[index]),
|
|
@@ -1762,6 +1459,7 @@ function resolveChartData(chart, document, options = {}) {
|
|
|
1762
1459
|
rows: out,
|
|
1763
1460
|
...source ? { source } : {},
|
|
1764
1461
|
...datasetId !== void 0 ? { dataset: datasetId } : {},
|
|
1462
|
+
...combo ? { combo } : {},
|
|
1765
1463
|
diagnostics
|
|
1766
1464
|
};
|
|
1767
1465
|
}
|
|
@@ -1778,18 +1476,18 @@ function chartNumberFixes(chart, document, options) {
|
|
|
1778
1476
|
if (!candidates.size) return fixes;
|
|
1779
1477
|
const data = chart.data;
|
|
1780
1478
|
let columns2;
|
|
1781
|
-
let
|
|
1479
|
+
let rows3;
|
|
1782
1480
|
let columnsPath;
|
|
1783
1481
|
let rowsPath;
|
|
1784
1482
|
if (isDatasetRef(data)) {
|
|
1785
1483
|
const dataset = datasetsOf(document)[data.dataset];
|
|
1786
1484
|
columns2 = dataset.columns;
|
|
1787
|
-
|
|
1485
|
+
rows3 = dataset.rows;
|
|
1788
1486
|
columnsPath = at("/datasets", data.dataset, "columns");
|
|
1789
1487
|
rowsPath = at("/datasets", data.dataset, "rows");
|
|
1790
1488
|
} else {
|
|
1791
1489
|
columns2 = data.columns;
|
|
1792
|
-
|
|
1490
|
+
rows3 = data.rows;
|
|
1793
1491
|
columnsPath = at(options.path ?? "", "data", "columns");
|
|
1794
1492
|
rowsPath = at(options.path ?? "", "data", "rows");
|
|
1795
1493
|
}
|
|
@@ -1797,7 +1495,7 @@ function chartNumberFixes(chart, document, options) {
|
|
|
1797
1495
|
const header = columns2[column];
|
|
1798
1496
|
const name = columnName(header);
|
|
1799
1497
|
if (name === void 0 || columnFormat(header) !== void 0) continue;
|
|
1800
|
-
const fix = columnFix(
|
|
1498
|
+
const fix = columnFix(rows3, column, rowsPath);
|
|
1801
1499
|
if (!fix) continue;
|
|
1802
1500
|
fixes.set(column, {
|
|
1803
1501
|
patches: [...fix.patches, { op: "replace", path: at(columnsPath, column), value: record3(header) ? { ...header, format: fix.format } : { name, format: fix.format } }],
|
|
@@ -1808,14 +1506,14 @@ function chartNumberFixes(chart, document, options) {
|
|
|
1808
1506
|
}
|
|
1809
1507
|
return fixes;
|
|
1810
1508
|
}
|
|
1811
|
-
function columnFix(
|
|
1509
|
+
function columnFix(rows3, column, rowsPath) {
|
|
1812
1510
|
const cells = [];
|
|
1813
1511
|
let prefix;
|
|
1814
1512
|
let suffix;
|
|
1815
1513
|
let grouping = false;
|
|
1816
1514
|
let wide = false;
|
|
1817
1515
|
const decimals = [];
|
|
1818
|
-
for (const [index, row] of
|
|
1516
|
+
for (const [index, row] of rows3.entries()) {
|
|
1819
1517
|
const cell = Array.isArray(row) && column < row.length ? row[column] : null;
|
|
1820
1518
|
if (cell === null || cell === void 0 || cell === "") continue;
|
|
1821
1519
|
const patch = chartNumber(cell) === null;
|
|
@@ -1870,12 +1568,12 @@ function resolveTableData(table, document, options = {}) {
|
|
|
1870
1568
|
const columnsPath = at("/datasets", id, "columns");
|
|
1871
1569
|
formatDiagnostics(dataset.columns, columnsPath, diagnostics);
|
|
1872
1570
|
const selection = selectFields(dataset.columns, table.fields, at(base, "fields"), columnsPath, diagnostics);
|
|
1873
|
-
const
|
|
1874
|
-
return { columns: selection.columns, rows:
|
|
1571
|
+
const rows4 = dataset.rows.map((row) => selection.indices.map((index) => Array.isArray(row) && index < row.length ? row[index] : null));
|
|
1572
|
+
return { columns: selection.columns, rows: rows4, formats: selection.formats, dataset: id, diagnostics };
|
|
1875
1573
|
}
|
|
1876
1574
|
const columns2 = Array.isArray(table.columns) ? table.columns : void 0;
|
|
1877
|
-
const
|
|
1878
|
-
const width = Math.max(columns2?.length ?? 0, ...
|
|
1575
|
+
const rows3 = Array.isArray(table.rows) ? table.rows.filter(Array.isArray) : [];
|
|
1576
|
+
const width = Math.max(columns2?.length ?? 0, ...rows3.map((row) => row.length), 0);
|
|
1879
1577
|
const formats = Array.from({ length: width }, (_, index) => {
|
|
1880
1578
|
const header = columns2?.[index];
|
|
1881
1579
|
return columnFormat(header) ?? cellFormat(header);
|
|
@@ -1893,7 +1591,7 @@ function resolveTableData(table, document, options = {}) {
|
|
|
1893
1591
|
check(cell, at(base, "rows", rowIndex, index));
|
|
1894
1592
|
});
|
|
1895
1593
|
});
|
|
1896
|
-
return { ...columns2 ? { columns: columns2 } : {}, rows:
|
|
1594
|
+
return { ...columns2 ? { columns: columns2 } : {}, rows: rows3, formats, diagnostics };
|
|
1897
1595
|
}
|
|
1898
1596
|
function tableCellDisplayValue(cell, columnFormat2) {
|
|
1899
1597
|
if (record3(cell) && own(cell, "value")) {
|
|
@@ -2019,6 +1717,38 @@ function intrinsicImageAspect(value, assets) {
|
|
|
2019
1717
|
return size ? size.width / size.height : void 0;
|
|
2020
1718
|
}
|
|
2021
1719
|
|
|
1720
|
+
// src/design-hints.ts
|
|
1721
|
+
var DESIGN_HINT_KEYS = ["titleAlignment", "contentAlignment", "contentBox", "contentDirection", "chartPrimary", "imageFill", "listBullet"];
|
|
1722
|
+
var ALIGNMENTS = ["left", "center", "right"];
|
|
1723
|
+
var VALUES = {
|
|
1724
|
+
titleAlignment: ALIGNMENTS,
|
|
1725
|
+
contentAlignment: ALIGNMENTS,
|
|
1726
|
+
contentBox: "boolean",
|
|
1727
|
+
contentDirection: ["horizontal", "vertical"],
|
|
1728
|
+
chartPrimary: ["none", "top", "bottom", "left", "right"],
|
|
1729
|
+
imageFill: ["crop", "fit"],
|
|
1730
|
+
listBullet: ["character", "image"]
|
|
1731
|
+
};
|
|
1732
|
+
var accepts = (key, value) => VALUES[key] === "boolean" ? typeof value === "boolean" : VALUES[key].includes(value);
|
|
1733
|
+
var object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1734
|
+
function resolveDesignHints(options = {}) {
|
|
1735
|
+
const slide = object(object(options.slide).design), host = object(options.deck), deck = object(object(options.presentation).design), layout = object(object(options.layout).design);
|
|
1736
|
+
const index = options.slideIndex ?? 0;
|
|
1737
|
+
const result = { sources: {}, paths: {} };
|
|
1738
|
+
const set2 = (key, value, source, path) => {
|
|
1739
|
+
result[key] = value;
|
|
1740
|
+
result.sources[key] = source;
|
|
1741
|
+
result.paths[key] = path;
|
|
1742
|
+
};
|
|
1743
|
+
for (const key of DESIGN_HINT_KEYS) {
|
|
1744
|
+
if (accepts(key, slide[key])) set2(key, slide[key], "slide", `slides.${index}.design.${key}`);
|
|
1745
|
+
else if (accepts(key, host[key])) set2(key, host[key], "deck", `design.${key}`);
|
|
1746
|
+
else if (accepts(key, deck[key])) set2(key, deck[key], "deck", `design.${key}`);
|
|
1747
|
+
else if (accepts(key, layout[key])) set2(key, layout[key], "layout", `slides.${index}.layout`);
|
|
1748
|
+
}
|
|
1749
|
+
return result;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
2022
1752
|
// src/reading-order.ts
|
|
2023
1753
|
function visualReadingOrder(items, direction = "ltr") {
|
|
2024
1754
|
const index = new Map(items.map((item, i) => [item, i]));
|
|
@@ -2028,18 +1758,18 @@ function visualReadingOrder(items, direction = "ltr") {
|
|
|
2028
1758
|
function readingRows(items) {
|
|
2029
1759
|
const index = new Map(items.map((item, i) => [item, i]));
|
|
2030
1760
|
const sorted = [...items].sort((a, b) => a.box.y - b.box.y || a.box.x - b.box.x || index.get(a) - index.get(b));
|
|
2031
|
-
const
|
|
1761
|
+
const rows3 = [];
|
|
2032
1762
|
for (const item of sorted) {
|
|
2033
1763
|
const centre = item.box.y + item.box.height / 2;
|
|
2034
|
-
const row =
|
|
1764
|
+
const row = rows3.find((candidate) => centre >= candidate.top && centre <= candidate.bottom);
|
|
2035
1765
|
if (row) {
|
|
2036
1766
|
row.items.push(item);
|
|
2037
1767
|
row.top = Math.min(row.top, item.box.y);
|
|
2038
1768
|
row.bottom = Math.max(row.bottom, item.box.y + item.box.height);
|
|
2039
|
-
} else
|
|
1769
|
+
} else rows3.push({ top: item.box.y, bottom: item.box.y + item.box.height, items: [item] });
|
|
2040
1770
|
}
|
|
2041
|
-
|
|
2042
|
-
return
|
|
1771
|
+
rows3.sort((a, b) => a.top - b.top);
|
|
1772
|
+
return rows3.map((row) => row.items.sort((a, b) => index.get(a) - index.get(b)));
|
|
2043
1773
|
}
|
|
2044
1774
|
|
|
2045
1775
|
// src/direction.ts
|
|
@@ -2083,6 +1813,12 @@ function paragraphDirectionAt(text2, deckDirection) {
|
|
|
2083
1813
|
}
|
|
2084
1814
|
|
|
2085
1815
|
// src/script-fonts.ts
|
|
1816
|
+
function normalizeLanguageFamily(value) {
|
|
1817
|
+
if (value === "latin") return "latin";
|
|
1818
|
+
if (value === "ea" || value === "eastAsian") return "ea";
|
|
1819
|
+
if (value === "cs" || value === "complexScript") return "cs";
|
|
1820
|
+
return void 0;
|
|
1821
|
+
}
|
|
2086
1822
|
var eastAsianScripts = /* @__PURE__ */ new Set(["Hani", "Hans", "Hant", "Hanb", "Jpan", "Kore", "Hang", "Jamo", "Hira", "Kana", "Hrkt", "Bopo", "Yiii"]);
|
|
2087
1823
|
var complexScripts = /* @__PURE__ */ new Set([
|
|
2088
1824
|
"Arab",
|
|
@@ -2253,13 +1989,8 @@ function pairFamilies(value) {
|
|
|
2253
1989
|
function schemeServesLanguage(scheme, language) {
|
|
2254
1990
|
const entries = Array.isArray(scheme.languages) ? scheme.languages.filter((entry) => typeof entry === "string") : [];
|
|
2255
1991
|
if (entries.length === 0) return true;
|
|
2256
|
-
const
|
|
2257
|
-
|
|
2258
|
-
const base = name.replace(/\s*\([^)]*\)\s*$/, "");
|
|
2259
|
-
return entries.some((entry) => {
|
|
2260
|
-
const value = entry.trim().toLowerCase();
|
|
2261
|
-
return value === name || value === base;
|
|
2262
|
-
});
|
|
1992
|
+
const id = text(language.id);
|
|
1993
|
+
return id !== void 0 && entries.includes(id);
|
|
2263
1994
|
}
|
|
2264
1995
|
function resolveScriptFonts(input, options = {}) {
|
|
2265
1996
|
const document = isRecord(input) ? input : {};
|
|
@@ -2291,16 +2022,16 @@ function resolveScriptFonts(input, options = {}) {
|
|
|
2291
2022
|
const scriptRole = scriptFontRole(script);
|
|
2292
2023
|
const declaredDirection = record6.direction;
|
|
2293
2024
|
const direction = declaredDirection === "rtl" || declaredDirection === "ltr" ? declaredDirection : rtlScripts.has(script) ? "rtl" : "ltr";
|
|
2294
|
-
const app = options.app ?? "
|
|
2295
|
-
const preferred = app === "
|
|
2296
|
-
const alternate = app === "
|
|
2025
|
+
const app = options.app ?? "powerpoint";
|
|
2026
|
+
const preferred = app === "google-slides" ? record6.googleFontScheme : record6.fontScheme;
|
|
2027
|
+
const alternate = app === "google-slides" ? record6.fontScheme : record6.googleFontScheme;
|
|
2297
2028
|
const languageScheme = resolveReference(lookup, "fontSchemes", preferred) ?? resolveReference(lookup, "fontSchemes", alternate);
|
|
2298
2029
|
const languageFamilies = pairFamilies(languageScheme);
|
|
2299
2030
|
const schemeAdmitsLanguage = schemeServesLanguage(scheme, record6);
|
|
2300
2031
|
const slot = (role, family) => {
|
|
2301
2032
|
const explicit = pairFamilies(scheme[role]);
|
|
2302
2033
|
if (explicit) return { ...explicit, source: "fontScheme" };
|
|
2303
|
-
if (scheme.languageFamily === family && schemeAdmitsLanguage) return { ...latin, source: "schemeFamily" };
|
|
2034
|
+
if (normalizeLanguageFamily(scheme.languageFamily) === family && schemeAdmitsLanguage) return { ...latin, source: "schemeFamily" };
|
|
2304
2035
|
if (scriptRole === role && languageFamilies) return { ...languageFamilies, source: "language" };
|
|
2305
2036
|
return { heading: latin.heading, body: latin.body, source: "latin" };
|
|
2306
2037
|
};
|
|
@@ -2403,10 +2134,10 @@ function listNumbers(items, numbering) {
|
|
|
2403
2134
|
const levels = resolveNumbering(numbering);
|
|
2404
2135
|
const counters = [];
|
|
2405
2136
|
return items.map((item, index) => {
|
|
2406
|
-
const
|
|
2407
|
-
const level =
|
|
2137
|
+
const object2 = isObject(item) ? item : void 0;
|
|
2138
|
+
const level = object2?.level === void 0 ? 0 : object2.level;
|
|
2408
2139
|
if (typeof level !== "number" || !Number.isInteger(level) || level < 0) throw new RangeError("List levels must be nonnegative integers.");
|
|
2409
|
-
const own2 =
|
|
2140
|
+
const own2 = object2?.start;
|
|
2410
2141
|
if (own2 !== void 0 && (typeof own2 !== "number" || !Number.isInteger(own2) || own2 < 1 || own2 > MAX_NUMBERING_VALUE)) throw new RangeError(`A list item start must be an integer from 1 to ${MAX_NUMBERING_VALUE}.`);
|
|
2411
2142
|
const { style: authored, start, suffix } = numberingAtLevel(levels, level);
|
|
2412
2143
|
const previous = counters[level];
|
|
@@ -2425,8 +2156,8 @@ function sliceNumberedItems(items, numbering, from, to = items.length) {
|
|
|
2425
2156
|
const wanted = whole[from + index].value;
|
|
2426
2157
|
if (listNumbers(result.slice(0, index + 1), numbering)[index].value === wanted) continue;
|
|
2427
2158
|
const item = result[index];
|
|
2428
|
-
const
|
|
2429
|
-
result[index] = { ...
|
|
2159
|
+
const object2 = isObject(item) ? item : { text: item };
|
|
2160
|
+
result[index] = { ...object2, start: wanted };
|
|
2430
2161
|
}
|
|
2431
2162
|
return result;
|
|
2432
2163
|
}
|
|
@@ -2479,6 +2210,7 @@ var schemeColorRoles = /* @__PURE__ */ new Set([
|
|
|
2479
2210
|
"accent",
|
|
2480
2211
|
"background",
|
|
2481
2212
|
"surface",
|
|
2213
|
+
"surfaceAlt",
|
|
2482
2214
|
"text",
|
|
2483
2215
|
"textSecondary"
|
|
2484
2216
|
]);
|
|
@@ -2522,6 +2254,11 @@ function resolveColorRef(reference, options) {
|
|
|
2522
2254
|
const roleKey = reference;
|
|
2523
2255
|
const fromRoles = roles?.[roleKey];
|
|
2524
2256
|
if (fromRoles) return normalizeHexColor(fromRoles) ?? fallback;
|
|
2257
|
+
if (reference === "surfaceAlt") {
|
|
2258
|
+
const surface = resolveColorRef("surface", { colorScheme, roles, variables, fallback: "#FFFFFF" });
|
|
2259
|
+
const text2 = resolveColorRef("text", { colorScheme, roles, variables, fallback: textColorForFill(surface, "#000000") });
|
|
2260
|
+
return surfaceAltColor(surface, text2);
|
|
2261
|
+
}
|
|
2525
2262
|
const fromScheme = normalizeHexColor(colorScheme[reference]);
|
|
2526
2263
|
if (fromScheme) return fromScheme;
|
|
2527
2264
|
const slot = defaultRoleSlots[reference];
|
|
@@ -2530,6 +2267,52 @@ function resolveColorRef(reference, options) {
|
|
|
2530
2267
|
if (schemeColorSlots.has(reference)) return schemeSlot(colorScheme, reference, fallback);
|
|
2531
2268
|
return fallback;
|
|
2532
2269
|
}
|
|
2270
|
+
var DARK_BACKGROUND_LUMINANCE = 0.179;
|
|
2271
|
+
function isDarkColor(color) {
|
|
2272
|
+
const hex = normalizeHexColor(color);
|
|
2273
|
+
const value = hex ? luminance(hex) : void 0;
|
|
2274
|
+
return value !== void 0 && value < DARK_BACKGROUND_LUMINANCE;
|
|
2275
|
+
}
|
|
2276
|
+
function defaultSlideBackground(colorScheme) {
|
|
2277
|
+
return keepAlpha(colorScheme.background) ?? slotKeepingAlpha(colorScheme, "light1", "#FFFFFF");
|
|
2278
|
+
}
|
|
2279
|
+
function keepAlpha(value) {
|
|
2280
|
+
if (typeof value !== "string") return void 0;
|
|
2281
|
+
const hex = value.trim();
|
|
2282
|
+
if (/^#[0-9a-f]{8}$/i.test(hex)) return hex.toUpperCase();
|
|
2283
|
+
return normalizeHexColor(hex);
|
|
2284
|
+
}
|
|
2285
|
+
function slotKeepingAlpha(colorScheme, slot, fallback) {
|
|
2286
|
+
return keepAlpha(colorScheme[slot]) ?? fallback;
|
|
2287
|
+
}
|
|
2288
|
+
var DEFAULT_HYPERLINK = "#0563C1";
|
|
2289
|
+
var DEFAULT_FOLLOWED_HYPERLINK = "#954F72";
|
|
2290
|
+
var MIN_LINK_CONTRAST = 4.5;
|
|
2291
|
+
function readableLink(link, background, text2) {
|
|
2292
|
+
const linkHex = normalizeHexColor(link), backgroundHex = normalizeHexColor(background);
|
|
2293
|
+
const contrast2 = linkHex && backgroundHex ? colorContrast(linkHex, backgroundHex) : void 0;
|
|
2294
|
+
return contrast2 !== void 0 && contrast2 < MIN_LINK_CONTRAST ? text2 : link;
|
|
2295
|
+
}
|
|
2296
|
+
function resolveColorRoles(colorScheme, options = {}) {
|
|
2297
|
+
const slot = (name, fallback) => slotKeepingAlpha(colorScheme, name, fallback);
|
|
2298
|
+
const background = keepAlpha(options.background) ?? defaultSlideBackground(colorScheme);
|
|
2299
|
+
const dark = isDarkColor(background);
|
|
2300
|
+
const text2 = dark ? slot("light1", "#FFFFFF") : keepAlpha(colorScheme.text) ?? slot("dark1", "#111827");
|
|
2301
|
+
const surface = keepAlpha(colorScheme.surface) ?? (dark ? slot("dark2", "#1E293B") : slot("light2", "#F8FAFC"));
|
|
2302
|
+
return {
|
|
2303
|
+
primary: keepAlpha(colorScheme.primary) ?? slot("accent1", "#2563EB"),
|
|
2304
|
+
secondary: keepAlpha(colorScheme.secondary) ?? slot("accent2", "#0F766E"),
|
|
2305
|
+
accent: keepAlpha(colorScheme.accent) ?? slot("accent3", "#F59E0B"),
|
|
2306
|
+
background,
|
|
2307
|
+
surface,
|
|
2308
|
+
surfaceAlt: surfaceAltColor(surface, text2),
|
|
2309
|
+
text: text2,
|
|
2310
|
+
textSecondary: keepAlpha(colorScheme.textSecondary) ?? (dark ? slot("light2", "#E2E8F0") : slot("dark2", "#334155")),
|
|
2311
|
+
hyperlink: readableLink(slot("hyperlink", DEFAULT_HYPERLINK), background, text2),
|
|
2312
|
+
followedHyperlink: slot("followedHyperlink", DEFAULT_FOLLOWED_HYPERLINK),
|
|
2313
|
+
dark
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2533
2316
|
function luminance(value) {
|
|
2534
2317
|
if (typeof value !== "string") return void 0;
|
|
2535
2318
|
let hex = value.trim();
|
|
@@ -2547,19 +2330,19 @@ function colorContrast(foreground, background) {
|
|
|
2547
2330
|
return a === void 0 || b === void 0 ? void 0 : (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
|
|
2548
2331
|
}
|
|
2549
2332
|
function textColorForFill(fill, preferred) {
|
|
2550
|
-
const background = luminance(fill),
|
|
2551
|
-
if (background === void 0 ||
|
|
2333
|
+
const background = luminance(fill), contrast2 = colorContrast(preferred, fill);
|
|
2334
|
+
if (background === void 0 || contrast2 === void 0 || contrast2 >= 4.5) return preferred;
|
|
2552
2335
|
return (background + 0.05) / 0.05 >= 1.05 / (background + 0.05) ? "#000000" : "#FFFFFF";
|
|
2553
2336
|
}
|
|
2554
2337
|
function chartColorForFill(fill, preferred) {
|
|
2555
|
-
const
|
|
2556
|
-
if (
|
|
2338
|
+
const contrast2 = colorContrast(preferred, fill);
|
|
2339
|
+
if (contrast2 === void 0 || contrast2 >= 3) return preferred;
|
|
2557
2340
|
let hex = preferred.trim();
|
|
2558
2341
|
if (hex.length === 4) hex = `#${[...hex.slice(1)].map((c) => c + c).join("")}`;
|
|
2559
|
-
const
|
|
2342
|
+
const channels2 = [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
|
|
2560
2343
|
for (let step = 1; step <= 255; step++) {
|
|
2561
2344
|
const candidates = [0, 255].map((target) => {
|
|
2562
|
-
const color = `#${
|
|
2345
|
+
const color = `#${channels2.map((channel) => Math.round(channel + (target - channel) * step / 255).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
|
|
2563
2346
|
return { color, contrast: colorContrast(color, fill) ?? 0 };
|
|
2564
2347
|
}).sort((a, b) => b.contrast - a.contrast);
|
|
2565
2348
|
const best = candidates[0];
|
|
@@ -2581,8 +2364,8 @@ var toLinear = (channel) => {
|
|
|
2581
2364
|
return n <= 0.04045 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
|
|
2582
2365
|
};
|
|
2583
2366
|
var fromLinear = (value) => 255 * (value <= 31308e-7 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - 0.055);
|
|
2584
|
-
function labOf(
|
|
2585
|
-
const [r, g, b] =
|
|
2367
|
+
function labOf(channels2) {
|
|
2368
|
+
const [r, g, b] = channels2.map(toLinear);
|
|
2586
2369
|
const f = (t) => t > 216 / 24389 ? Math.cbrt(t) : (24389 / 27 * t + 16) / 116;
|
|
2587
2370
|
const fx = f((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / D65[0]), fy = f(0.2126729 * r + 0.7151522 * g + 0.072175 * b), fz = f((0.0193339 * r + 0.119192 * g + 0.9503041 * b) / D65[2]);
|
|
2588
2371
|
return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];
|
|
@@ -2598,21 +2381,21 @@ function labToLinear([l, a, b]) {
|
|
|
2598
2381
|
];
|
|
2599
2382
|
return rgb.every((channel) => channel >= -5e-4 && channel <= 1.0005) ? rgb : void 0;
|
|
2600
2383
|
}
|
|
2601
|
-
var hexOfChannels = (
|
|
2384
|
+
var hexOfChannels = (channels2) => `#${channels2.map((channel) => Math.max(0, Math.min(255, Math.round(channel))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
|
|
2602
2385
|
function labWithLightness(l, a, b) {
|
|
2603
2386
|
const chroma = Math.hypot(a, b), hue = Math.atan2(b, a);
|
|
2604
2387
|
const at3 = (scale) => labToLinear([l, Math.cos(hue) * chroma * scale, Math.sin(hue) * chroma * scale]);
|
|
2605
|
-
let
|
|
2606
|
-
if (!
|
|
2388
|
+
let linear2 = at3(1);
|
|
2389
|
+
if (!linear2) {
|
|
2607
2390
|
let low = 0, high = 1;
|
|
2608
2391
|
for (let step = 0; step < 24; step++) {
|
|
2609
2392
|
const mid = (low + high) / 2;
|
|
2610
2393
|
if (at3(mid)) low = mid;
|
|
2611
2394
|
else high = mid;
|
|
2612
2395
|
}
|
|
2613
|
-
|
|
2396
|
+
linear2 = at3(low) ?? [0, 0, 0];
|
|
2614
2397
|
}
|
|
2615
|
-
return hexOfChannels(
|
|
2398
|
+
return hexOfChannels(linear2.map((channel) => fromLinear(Math.max(0, Math.min(1, channel)))));
|
|
2616
2399
|
}
|
|
2617
2400
|
function labDifference(a, b) {
|
|
2618
2401
|
return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
|
|
@@ -2621,15 +2404,15 @@ var CHART_SERIES_SHORTFALL_WEIGHT = 8;
|
|
|
2621
2404
|
function chartPaletteForFill(fill, palette) {
|
|
2622
2405
|
const opaqueFill = colorContrast(fill, fill) !== void 0;
|
|
2623
2406
|
const preferredLab = palette.map((color) => {
|
|
2624
|
-
const
|
|
2625
|
-
return
|
|
2407
|
+
const channels2 = opaqueChannels(color);
|
|
2408
|
+
return channels2 ? labOf(channels2) : void 0;
|
|
2626
2409
|
});
|
|
2627
2410
|
const adjusted = palette.map((color) => chartColorForFill(fill, color));
|
|
2628
2411
|
const kept = palette.map((color, index) => opaqueFill && preferredLab[index] !== void 0 && adjusted[index] === color);
|
|
2629
2412
|
const placed = palette.map((_, index) => kept[index] || !opaqueFill || !preferredLab[index] ? adjusted[index] : void 0);
|
|
2630
2413
|
const placedLab = placed.map((color) => {
|
|
2631
|
-
const
|
|
2632
|
-
return
|
|
2414
|
+
const channels2 = color === void 0 ? void 0 : opaqueChannels(color);
|
|
2415
|
+
return channels2 ? labOf(channels2) : void 0;
|
|
2633
2416
|
});
|
|
2634
2417
|
palette.forEach((_, index) => {
|
|
2635
2418
|
const wanted = preferredLab[index], base = adjusted[index];
|
|
@@ -2653,8 +2436,8 @@ function chartPaletteForFill(fill, palette) {
|
|
|
2653
2436
|
}
|
|
2654
2437
|
let best = { color: base, lab: baseLab, cost: cost({ moved: 0, ...start }), moved: 0 };
|
|
2655
2438
|
for (let step = 0; step <= 400; step++) {
|
|
2656
|
-
const color = labWithLightness(step / 4, wanted[1], wanted[2]),
|
|
2657
|
-
if (
|
|
2439
|
+
const color = labWithLightness(step / 4, wanted[1], wanted[2]), contrast2 = colorContrast(color, fill);
|
|
2440
|
+
if (contrast2 === void 0 || contrast2 < 3) continue;
|
|
2658
2441
|
const lab = labOf(opaqueChannels(color)), moved = Math.abs(lab[0] - baseLab[0]), total = cost({ moved, ...shortfall(lab) });
|
|
2659
2442
|
if (total < best.cost - 1e-9 || Math.abs(total - best.cost) <= 1e-9 && moved < best.moved) best = { color, lab, cost: total, moved };
|
|
2660
2443
|
}
|
|
@@ -2663,6 +2446,1113 @@ function chartPaletteForFill(fill, palette) {
|
|
|
2663
2446
|
});
|
|
2664
2447
|
return placed;
|
|
2665
2448
|
}
|
|
2449
|
+
var CHART_HIGHLIGHT_MUTED_MIX = 0.3;
|
|
2450
|
+
var CHART_HIGHLIGHT_MUTED_MIN_CONTRAST = 1.6;
|
|
2451
|
+
var mixChannels = (from, to, amount) => hexOfChannels(from.map((channel, index) => channel + (to[index] - channel) * amount));
|
|
2452
|
+
function chartHighlightColors(surface, primary, text2) {
|
|
2453
|
+
const fill = normalizeHexColor(surface) ?? "#FFFFFF";
|
|
2454
|
+
const accent = chartColorForFill(fill, normalizeHexColor(primary) ?? "#000000");
|
|
2455
|
+
const ink = normalizeHexColor(text2) ?? textColorForFill(fill, "#000000");
|
|
2456
|
+
const from = opaqueChannels(fill), to = opaqueChannels(ink);
|
|
2457
|
+
let muted = mixChannels(from, to, CHART_HIGHLIGHT_MUTED_MIX);
|
|
2458
|
+
for (let amount = CHART_HIGHLIGHT_MUTED_MIX; (colorContrast(muted, fill) ?? Infinity) < CHART_HIGHLIGHT_MUTED_MIN_CONTRAST && amount < 1; ) {
|
|
2459
|
+
amount = Math.min(1, amount + 0.02);
|
|
2460
|
+
muted = mixChannels(from, to, amount);
|
|
2461
|
+
}
|
|
2462
|
+
return { accent, muted };
|
|
2463
|
+
}
|
|
2464
|
+
var SURFACE_ALT_MIX = 0.1;
|
|
2465
|
+
var SURFACE_ALT_MIN_CONTRAST = 1.1;
|
|
2466
|
+
function surfaceAltColor(surface, text2) {
|
|
2467
|
+
const fill = normalizeHexColor(surface) ?? "#FFFFFF";
|
|
2468
|
+
const ink = normalizeHexColor(text2) ?? textColorForFill(fill, "#000000");
|
|
2469
|
+
const from = opaqueChannels(fill), toText = opaqueChannels(ink);
|
|
2470
|
+
const step = (color) => (colorContrast(color, fill) ?? 1) >= SURFACE_ALT_MIN_CONTRAST;
|
|
2471
|
+
const readable = (color) => (colorContrast(ink, color) ?? 0) >= 4.5 || (colorContrast(ink, color) ?? 0) >= (colorContrast(ink, fill) ?? 0);
|
|
2472
|
+
for (let amount = SURFACE_ALT_MIX; amount <= 0.5 + 1e-9; amount += 0.02) {
|
|
2473
|
+
const band = mixChannels(from, toText, amount);
|
|
2474
|
+
if (!readable(band)) break;
|
|
2475
|
+
if (step(band)) return band;
|
|
2476
|
+
}
|
|
2477
|
+
const away = (luminance(ink) ?? 0) > (luminance(fill) ?? 0) ? [0, 0, 0] : [255, 255, 255];
|
|
2478
|
+
for (let amount = SURFACE_ALT_MIX; amount <= 1 + 1e-9; amount += 0.02) {
|
|
2479
|
+
const band = mixChannels(from, away, Math.min(1, amount));
|
|
2480
|
+
if (step(band)) return band;
|
|
2481
|
+
}
|
|
2482
|
+
return mixChannels(from, toText, SURFACE_ALT_MIX);
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
// src/legible-color.ts
|
|
2486
|
+
var channels = (hex) => [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
|
|
2487
|
+
var toHex = (values) => `#${values.map((value) => Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
|
|
2488
|
+
var linear = (value) => {
|
|
2489
|
+
const n = value / 255;
|
|
2490
|
+
return n <= 0.04045 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
|
|
2491
|
+
};
|
|
2492
|
+
var luminance2 = (hex) => {
|
|
2493
|
+
const [r, g, b] = channels(hex);
|
|
2494
|
+
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
|
|
2495
|
+
};
|
|
2496
|
+
var contrast = (a, b) => {
|
|
2497
|
+
const x = luminance2(a), y = luminance2(b);
|
|
2498
|
+
return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
|
|
2499
|
+
};
|
|
2500
|
+
var normalize = (value) => {
|
|
2501
|
+
if (typeof value !== "string") return void 0;
|
|
2502
|
+
const text2 = value.trim();
|
|
2503
|
+
if (/^#[0-9a-f]{3}$/i.test(text2)) return `#${[...text2.slice(1)].map((c) => c + c).join("")}`.toUpperCase();
|
|
2504
|
+
return /^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(text2) ? text2.slice(0, 7).toUpperCase() : void 0;
|
|
2505
|
+
};
|
|
2506
|
+
function toHsl(hex) {
|
|
2507
|
+
const [r, g, b] = channels(hex).map((value) => value / 255);
|
|
2508
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min;
|
|
2509
|
+
if (d === 0) return [0, 0, l];
|
|
2510
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
2511
|
+
const h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
2512
|
+
return [h * 60, s, l];
|
|
2513
|
+
}
|
|
2514
|
+
function fromHsl(h, s, l) {
|
|
2515
|
+
const hue = (h % 360 + 360) % 360, c = (1 - Math.abs(2 * l - 1)) * s, x = c * (1 - Math.abs(hue / 60 % 2 - 1)), m = l - c / 2;
|
|
2516
|
+
const [r, g, b] = hue < 60 ? [c, x, 0] : hue < 120 ? [x, c, 0] : hue < 180 ? [0, c, x] : hue < 240 ? [0, x, c] : hue < 300 ? [x, 0, c] : [c, 0, x];
|
|
2517
|
+
return toHex([(r + m) * 255, (g + m) * 255, (b + m) * 255]);
|
|
2518
|
+
}
|
|
2519
|
+
function legible(foreground, background, minimum) {
|
|
2520
|
+
if (contrast(foreground, background) >= minimum) return foreground;
|
|
2521
|
+
const [h, s, l] = toHsl(foreground), preferred = luminance2(background) < 0.5 ? 1 : -1;
|
|
2522
|
+
for (const direction of [preferred, -preferred]) {
|
|
2523
|
+
for (let step = 1; step <= 100; step++) {
|
|
2524
|
+
const lightness = l + direction * step / 100;
|
|
2525
|
+
if (lightness < 0 || lightness > 1) break;
|
|
2526
|
+
const candidate = fromHsl(h, s, lightness);
|
|
2527
|
+
if (contrast(candidate, background) >= minimum) return candidate;
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
return contrast("#FFFFFF", background) >= contrast("#000000", background) ? "#FFFFFF" : "#000000";
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
// src/code-syntax.ts
|
|
2534
|
+
var CODE_HIGHLIGHT_MAX_LENGTH = 2e5;
|
|
2535
|
+
var CODE_SYNTAX_MIN_CONTRAST = 4.5;
|
|
2536
|
+
var CODE_PANEL_BACKGROUND = "#111827";
|
|
2537
|
+
var CODE_PANEL_FOREGROUND = "#E5E7EB";
|
|
2538
|
+
var set = (words) => new Set((words ?? "").split(/\s+/).filter(Boolean));
|
|
2539
|
+
var JS_KEYWORDS = "break case catch class const continue debugger default delete do else enum export extends finally for from function if import in instanceof let new of return static super switch this throw try typeof var void while with yield async await as get set declare namespace module abstract implements interface private protected public readonly override keyof satisfies type is infer";
|
|
2540
|
+
var JS = { line: ["//"], block: [["/*", "*/"]], strings: "'\"`", keywords: JS_KEYWORDS, literals: "true false null undefined NaN Infinity", types: "string number boolean object symbol bigint never unknown any void", defs: { function: "function", class: "type", interface: "type", enum: "type", type: "type" }, capsTypes: true, calls: true, decorators: true };
|
|
2541
|
+
var C_LIKE_KEYWORDS = "auto break case catch char class const constexpr continue default delete do double else enum explicit extern false final float for friend goto if inline int long mutable namespace new noexcept nullptr operator override private protected public register return short signed sizeof static struct switch template this throw true try typedef typename union unsigned using virtual void volatile while";
|
|
2542
|
+
var LANGUAGES = {
|
|
2543
|
+
javascript: JS,
|
|
2544
|
+
typescript: JS,
|
|
2545
|
+
python: { line: ["#"], strings: `'"`, triple: ['"""', "'''"], keywords: "and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield match case self cls", literals: "True False None", types: "int float str bool bytes list dict set tuple object type", defs: { def: "function", class: "type" }, capsTypes: true, calls: true, decorators: true },
|
|
2546
|
+
rust: { line: ["//"], block: [["/*", "*/"]], strings: '"', rawStrings: "r", keywords: "as async await break const continue crate dyn else enum extern fn for if impl in let loop match mod move mut pub ref return self Self static struct super trait type unsafe use where while", literals: "true false", types: "i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 bool char str String Vec Option Result Box", defs: { fn: "function", struct: "type", enum: "type", trait: "type", type: "type", mod: "type" }, capsTypes: true, calls: true, macros: true },
|
|
2547
|
+
go: { line: ["//"], block: [["/*", "*/"]], strings: "\"'`", noEscapes: "`", keywords: "break case chan const continue default defer else fallthrough for func go goto if import interface map package range return select struct switch type var", literals: "true false nil iota", types: "int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex64 complex128 string bool byte rune error any", defs: { func: "function", type: "type" }, capsTypes: true, calls: true },
|
|
2548
|
+
bash: { line: ["#"], strings: `'"`, noEscapes: "'", keywords: "if then else elif fi for while until do done case esac in function select time return exit break continue export local readonly declare unset set shift source alias trap eval exec", literals: "true false", variables: true, calls: false },
|
|
2549
|
+
json: { line: ["//"], block: [["/*", "*/"]], strings: '"', literals: "true false null", quotedKeys: true },
|
|
2550
|
+
yaml: { kind: "yaml" },
|
|
2551
|
+
toml: { kind: "ini", line: ["#"] },
|
|
2552
|
+
ini: { kind: "ini", line: ["#", ";"] },
|
|
2553
|
+
markup: { kind: "markup" },
|
|
2554
|
+
css: { kind: "css" },
|
|
2555
|
+
sql: { line: ["--"], block: [["/*", "*/"]], strings: `'"`, ci: true, keywords: "add all alter and any as asc between by case check column commit constraint create cross database default delete desc distinct drop else end exists foreign from full group having if in index inner insert into is join key left like limit not null offset on or order outer primary references replace right rollback select set table then top union unique update values view when where with", literals: "true false", types: "int integer bigint smallint decimal numeric float real double varchar char text date time timestamp boolean serial uuid json" },
|
|
2556
|
+
java: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, keywords: "abstract assert break case catch class const continue default do else enum extends final finally for goto if implements import instanceof interface native new package private protected public return static strictfp super switch synchronized this throw throws transient try var volatile while record sealed permits", literals: "true false null", types: "boolean byte char double float int long short void String Object", defs: { class: "type", interface: "type", enum: "type", record: "type" }, capsTypes: true, calls: true, decorators: true },
|
|
2557
|
+
csharp: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, keywords: "abstract as async await base break case catch checked class const continue default delegate do else enum event explicit extern finally fixed for foreach goto if implicit in interface internal is lock namespace new operator out override params private protected public readonly ref return sealed sizeof stackalloc static struct switch this throw try typeof unchecked unsafe using var virtual volatile while record init required", literals: "true false null", types: "bool byte char decimal double float int long object sbyte short string uint ulong ushort void dynamic", defs: { class: "type", interface: "type", struct: "type", enum: "type", record: "type" }, capsTypes: true, calls: true, decorators: false },
|
|
2558
|
+
kotlin: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, triple: ['"""'], keywords: "abstract actual annotation as break by catch class companion const constructor continue crossinline data do else enum expect external final finally for fun get if import in infix init inline inner interface internal is it lateinit lazy noinline object open operator out override package private protected public reified return sealed set super suspend tailrec this throw try typealias val var vararg when where while", literals: "true false null", types: "Int Long Short Byte Float Double Boolean Char String Unit Any Nothing", defs: { fun: "function", class: "type", interface: "type", object: "type" }, capsTypes: true, calls: true, decorators: true },
|
|
2559
|
+
swift: { line: ["//"], block: [["/*", "*/"]], strings: '"', triple: ['"""'], keywords: "actor as associatedtype async await break case catch class continue default defer deinit do else enum extension fallthrough fileprivate for func guard if import in init inout internal is let nonisolated open operator private protocol public repeat rethrows return self Self static struct subscript super switch throw throws try typealias var where while", literals: "true false nil", types: "Int Double Float Bool String Character Array Dictionary Set Optional Any", defs: { func: "function", class: "type", struct: "type", enum: "type", protocol: "type", extension: "type" }, capsTypes: true, calls: true, decorators: true },
|
|
2560
|
+
ruby: { line: ["#"], strings: `'"`, keywords: "alias and begin break case class def defined do else elsif end ensure for if in module next not or redo rescue retry return self super then undef unless until when while yield require require_relative include extend attr_accessor attr_reader attr_writer private protected public", literals: "true false nil", defs: { def: "function", class: "type", module: "type" }, capsTypes: true, calls: true },
|
|
2561
|
+
php: { line: ["//", "#"], block: [["/*", "*/"]], strings: `'"`, keywords: "abstract and array as break callable case catch class clone const continue declare default do echo else elseif empty enddeclare endfor endforeach endif endswitch endwhile extends final finally fn for foreach function global goto if implements include include_once instanceof insteadof interface isset list match namespace new or print private protected public readonly require require_once return static switch throw trait try unset use var while xor yield", literals: "true false null TRUE FALSE NULL", defs: { function: "function", class: "type", interface: "type", trait: "type" }, capsTypes: true, calls: true, variables: true },
|
|
2562
|
+
c: { line: ["//"], block: [["/*", "*/"]], strings: `"'`, keywords: C_LIKE_KEYWORDS, literals: "true false NULL nullptr", types: "size_t ssize_t int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t bool FILE", calls: true, capsTypes: false, directives: true, defs: { struct: "type", enum: "type", union: "type", class: "type" } },
|
|
2563
|
+
hcl: { line: ["#", "//"], block: [["/*", "*/"]], strings: '"', keywords: "resource data variable output locals module provider terraform for in if else dynamic content backend required_providers lifecycle", literals: "true false null", types: "string number bool list map set object tuple any", calls: true },
|
|
2564
|
+
dockerfile: { line: ["#"], strings: `'"`, keywords: "FROM RUN CMD LABEL MAINTAINER EXPOSE ENV ADD COPY ENTRYPOINT VOLUME USER WORKDIR ARG ONBUILD STOPSIGNAL HEALTHCHECK SHELL AS", variables: true }
|
|
2565
|
+
};
|
|
2566
|
+
var ALIASES = {
|
|
2567
|
+
js: "javascript",
|
|
2568
|
+
javascript: "javascript",
|
|
2569
|
+
mjs: "javascript",
|
|
2570
|
+
cjs: "javascript",
|
|
2571
|
+
jsx: "javascript",
|
|
2572
|
+
node: "javascript",
|
|
2573
|
+
nodejs: "javascript",
|
|
2574
|
+
ts: "typescript",
|
|
2575
|
+
typescript: "typescript",
|
|
2576
|
+
tsx: "typescript",
|
|
2577
|
+
mts: "typescript",
|
|
2578
|
+
cts: "typescript",
|
|
2579
|
+
python: "python",
|
|
2580
|
+
py: "python",
|
|
2581
|
+
python3: "python",
|
|
2582
|
+
py3: "python",
|
|
2583
|
+
rust: "rust",
|
|
2584
|
+
rs: "rust",
|
|
2585
|
+
go: "go",
|
|
2586
|
+
golang: "go",
|
|
2587
|
+
bash: "bash",
|
|
2588
|
+
sh: "bash",
|
|
2589
|
+
shell: "bash",
|
|
2590
|
+
zsh: "bash",
|
|
2591
|
+
console: "bash",
|
|
2592
|
+
shellscript: "bash",
|
|
2593
|
+
fish: "bash",
|
|
2594
|
+
json: "json",
|
|
2595
|
+
jsonc: "json",
|
|
2596
|
+
json5: "json",
|
|
2597
|
+
yaml: "yaml",
|
|
2598
|
+
yml: "yaml",
|
|
2599
|
+
toml: "toml",
|
|
2600
|
+
ini: "ini",
|
|
2601
|
+
conf: "ini",
|
|
2602
|
+
cfg: "ini",
|
|
2603
|
+
properties: "ini",
|
|
2604
|
+
env: "ini",
|
|
2605
|
+
markup: "markup",
|
|
2606
|
+
html: "markup",
|
|
2607
|
+
xml: "markup",
|
|
2608
|
+
svg: "markup",
|
|
2609
|
+
xhtml: "markup",
|
|
2610
|
+
vue: "markup",
|
|
2611
|
+
plist: "markup",
|
|
2612
|
+
css: "css",
|
|
2613
|
+
scss: "css",
|
|
2614
|
+
less: "css",
|
|
2615
|
+
sass: "css",
|
|
2616
|
+
sql: "sql",
|
|
2617
|
+
postgres: "sql",
|
|
2618
|
+
postgresql: "sql",
|
|
2619
|
+
mysql: "sql",
|
|
2620
|
+
sqlite: "sql",
|
|
2621
|
+
pgsql: "sql",
|
|
2622
|
+
java: "java",
|
|
2623
|
+
csharp: "csharp",
|
|
2624
|
+
cs: "csharp",
|
|
2625
|
+
"c#": "csharp",
|
|
2626
|
+
kotlin: "kotlin",
|
|
2627
|
+
kt: "kotlin",
|
|
2628
|
+
swift: "swift",
|
|
2629
|
+
ruby: "ruby",
|
|
2630
|
+
rb: "ruby",
|
|
2631
|
+
php: "php",
|
|
2632
|
+
c: "c",
|
|
2633
|
+
h: "c",
|
|
2634
|
+
cpp: "c",
|
|
2635
|
+
"c++": "c",
|
|
2636
|
+
cc: "c",
|
|
2637
|
+
cxx: "c",
|
|
2638
|
+
hpp: "c",
|
|
2639
|
+
hh: "c",
|
|
2640
|
+
objc: "c",
|
|
2641
|
+
hcl: "hcl",
|
|
2642
|
+
terraform: "hcl",
|
|
2643
|
+
tf: "hcl",
|
|
2644
|
+
tfvars: "hcl",
|
|
2645
|
+
dockerfile: "dockerfile",
|
|
2646
|
+
docker: "dockerfile"
|
|
2647
|
+
};
|
|
2648
|
+
var CODE_HIGHLIGHT_LANGUAGES = Object.freeze(Object.keys(LANGUAGES));
|
|
2649
|
+
function resolveCodeLanguage(language) {
|
|
2650
|
+
if (typeof language !== "string") return void 0;
|
|
2651
|
+
const key = language.trim().toLowerCase().replace(/^(?:language|lang)[-:]/, "").replace(/^\./, "");
|
|
2652
|
+
return Object.hasOwn(ALIASES, key) ? ALIASES[key] : void 0;
|
|
2653
|
+
}
|
|
2654
|
+
var IDENT = /[\p{L}_$][\p{L}\p{N}_$]*/uy;
|
|
2655
|
+
var NUMBER = /(?:0[xX][\da-fA-F_]+|0[bB][01_]+|0[oO][0-7_]+|\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)[a-zA-Z]{0,4}/y;
|
|
2656
|
+
var isIdentChar = (character) => character !== void 0 && /[\p{L}\p{N}_$]/u.test(character);
|
|
2657
|
+
function endOfLine(source, from) {
|
|
2658
|
+
const index = source.slice(from).search(/\r\n|\r|\n/);
|
|
2659
|
+
return index < 0 ? source.length : from + index;
|
|
2660
|
+
}
|
|
2661
|
+
function pushToken(tokens, start, end, kind2) {
|
|
2662
|
+
if (end <= start) return;
|
|
2663
|
+
const last = tokens[tokens.length - 1];
|
|
2664
|
+
if (last && last.kind === kind2 && last.end === start && kind2 !== "function" && kind2 !== "property") last.end = end;
|
|
2665
|
+
else tokens.push({ start, end, kind: kind2 });
|
|
2666
|
+
}
|
|
2667
|
+
function scanQuoted(source, from, quote, escapes, multiline) {
|
|
2668
|
+
let index = from + 1;
|
|
2669
|
+
while (index < source.length) {
|
|
2670
|
+
const character = source[index];
|
|
2671
|
+
if (escapes && character === "\\") {
|
|
2672
|
+
index += 2;
|
|
2673
|
+
continue;
|
|
2674
|
+
}
|
|
2675
|
+
if (character === quote) return index + 1;
|
|
2676
|
+
if (!multiline && (character === "\n" || character === "\r")) return index;
|
|
2677
|
+
index++;
|
|
2678
|
+
}
|
|
2679
|
+
return source.length;
|
|
2680
|
+
}
|
|
2681
|
+
function scanGeneric(source, def) {
|
|
2682
|
+
const tokens = [];
|
|
2683
|
+
const keywords = set(def.keywords), literals = set(def.literals), types = set(def.types);
|
|
2684
|
+
const fold = (word) => def.ci ? word.toLowerCase() : word;
|
|
2685
|
+
if (def.ci) for (const list of [keywords, literals, types]) for (const word of [...list]) {
|
|
2686
|
+
list.delete(word);
|
|
2687
|
+
list.add(word.toLowerCase());
|
|
2688
|
+
}
|
|
2689
|
+
const strings = def.strings ?? "", lineComments = def.line ?? [], blocks = def.block ?? [], triples = def.triple ?? [];
|
|
2690
|
+
let index = 0, pendingDef;
|
|
2691
|
+
const atLineStart = (position) => {
|
|
2692
|
+
let at3 = position - 1;
|
|
2693
|
+
while (at3 >= 0 && (source[at3] === " " || source[at3] === " ")) at3--;
|
|
2694
|
+
return at3 < 0 || source[at3] === "\n" || source[at3] === "\r";
|
|
2695
|
+
};
|
|
2696
|
+
while (index < source.length) {
|
|
2697
|
+
const character = source[index];
|
|
2698
|
+
if (/\s/.test(character)) {
|
|
2699
|
+
index++;
|
|
2700
|
+
continue;
|
|
2701
|
+
}
|
|
2702
|
+
const lineComment = lineComments.find((opener) => source.startsWith(opener, index));
|
|
2703
|
+
if (lineComment && !(lineComment === "#" && def.directives) && !(lineComment === "#" && def.variables && source[index - 1] === "$") && !(def.variables && lineComment === "#" && index > 0 && !/[\s;&|(]/.test(source[index - 1]))) {
|
|
2704
|
+
const end = endOfLine(source, index);
|
|
2705
|
+
pushToken(tokens, index, end, "comment");
|
|
2706
|
+
index = end;
|
|
2707
|
+
continue;
|
|
2708
|
+
}
|
|
2709
|
+
const block = blocks.find(([opener]) => source.startsWith(opener, index));
|
|
2710
|
+
if (block) {
|
|
2711
|
+
const close = source.indexOf(block[1], index + block[0].length);
|
|
2712
|
+
const end = close < 0 ? source.length : close + block[1].length;
|
|
2713
|
+
pushToken(tokens, index, end, "comment");
|
|
2714
|
+
index = end;
|
|
2715
|
+
continue;
|
|
2716
|
+
}
|
|
2717
|
+
if (def.directives && character === "#" && atLineStart(index)) {
|
|
2718
|
+
const match = /#[ \t]*\w+/y;
|
|
2719
|
+
match.lastIndex = index;
|
|
2720
|
+
const found = match.exec(source);
|
|
2721
|
+
if (found) {
|
|
2722
|
+
pushToken(tokens, index, index + found[0].length, "keyword");
|
|
2723
|
+
index += found[0].length;
|
|
2724
|
+
if (/include/.test(found[0])) {
|
|
2725
|
+
const header = /[ \t]*(<[^>\n]*>)/y;
|
|
2726
|
+
header.lastIndex = index;
|
|
2727
|
+
const matched = header.exec(source);
|
|
2728
|
+
if (matched) {
|
|
2729
|
+
const start = index + matched[0].length - matched[1].length;
|
|
2730
|
+
pushToken(tokens, start, start + matched[1].length, "string");
|
|
2731
|
+
index += matched[0].length;
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
continue;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
const triple = triples.find((opener) => source.startsWith(opener, index));
|
|
2738
|
+
if (triple) {
|
|
2739
|
+
const close = source.indexOf(triple, index + 3);
|
|
2740
|
+
const end = close < 0 ? source.length : close + 3;
|
|
2741
|
+
pushToken(tokens, index, end, "string");
|
|
2742
|
+
index = end;
|
|
2743
|
+
pendingDef = void 0;
|
|
2744
|
+
continue;
|
|
2745
|
+
}
|
|
2746
|
+
if (def.rawStrings && character === def.rawStrings && /^r#*"/.test(source.slice(index, index + 8)) && !isIdentChar(source[index - 1])) {
|
|
2747
|
+
const hashes = /^r(#*)"/.exec(source.slice(index, index + 8))[1];
|
|
2748
|
+
const close = source.indexOf(`"${hashes}`, index + 2 + hashes.length);
|
|
2749
|
+
const end = close < 0 ? source.length : close + 1 + hashes.length;
|
|
2750
|
+
pushToken(tokens, index, end, "string");
|
|
2751
|
+
index = end;
|
|
2752
|
+
continue;
|
|
2753
|
+
}
|
|
2754
|
+
if (strings.includes(character)) {
|
|
2755
|
+
if (def === LANGUAGES.rust && character === "'" && !/^'(?:\\.[^']*|[^\\'])'/.test(source.slice(index, index + 12))) {
|
|
2756
|
+
const match = /'[\p{L}_][\p{L}\p{N}_]*/uy;
|
|
2757
|
+
match.lastIndex = index;
|
|
2758
|
+
const found = match.exec(source);
|
|
2759
|
+
const end2 = index + (found ? found[0].length : 1);
|
|
2760
|
+
if (found) pushToken(tokens, index, end2, "type");
|
|
2761
|
+
index = end2;
|
|
2762
|
+
continue;
|
|
2763
|
+
}
|
|
2764
|
+
const escapes = !(def.noEscapes ?? "").includes(character);
|
|
2765
|
+
const multiline = character === "`";
|
|
2766
|
+
const end = scanQuoted(source, index, character, escapes, multiline);
|
|
2767
|
+
let kind2 = "string";
|
|
2768
|
+
if (def.quotedKeys) {
|
|
2769
|
+
const after = /^[ \t]*:/.exec(source.slice(end, end + 40));
|
|
2770
|
+
if (after) kind2 = "property";
|
|
2771
|
+
}
|
|
2772
|
+
pushToken(tokens, index, end, kind2);
|
|
2773
|
+
index = end;
|
|
2774
|
+
pendingDef = void 0;
|
|
2775
|
+
continue;
|
|
2776
|
+
}
|
|
2777
|
+
if (def.variables && character === "$") {
|
|
2778
|
+
const match = /\$(?:\{[^}\n]*\}|[A-Za-z_]\w*|[0-9@#?!$*-])/y;
|
|
2779
|
+
match.lastIndex = index;
|
|
2780
|
+
const found = match.exec(source);
|
|
2781
|
+
if (found) {
|
|
2782
|
+
pushToken(tokens, index, index + found[0].length, "property");
|
|
2783
|
+
index += found[0].length;
|
|
2784
|
+
continue;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
if (def.decorators && character === "@" && /[\p{L}_]/u.test(source[index + 1] ?? "")) {
|
|
2788
|
+
const match = /@[\p{L}_][\p{L}\p{N}_$.]*/uy;
|
|
2789
|
+
match.lastIndex = index;
|
|
2790
|
+
const found = match.exec(source);
|
|
2791
|
+
pushToken(tokens, index, index + found[0].length, "function");
|
|
2792
|
+
index += found[0].length;
|
|
2793
|
+
continue;
|
|
2794
|
+
}
|
|
2795
|
+
if (/\d/.test(character) && !isIdentChar(source[index - 1])) {
|
|
2796
|
+
NUMBER.lastIndex = index;
|
|
2797
|
+
const found = NUMBER.exec(source);
|
|
2798
|
+
if (found) {
|
|
2799
|
+
pushToken(tokens, index, index + found[0].length, "number");
|
|
2800
|
+
index += found[0].length;
|
|
2801
|
+
pendingDef = void 0;
|
|
2802
|
+
continue;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
if (def === LANGUAGES.python && /[rRbBfFuU]/.test(character) && /^[rRbBfFuU]{1,2}['"]/.test(source.slice(index, index + 3)) && !isIdentChar(source[index - 1])) {
|
|
2806
|
+
const prefix = /^[rRbBfFuU]{1,2}/.exec(source.slice(index, index + 3))[0].length;
|
|
2807
|
+
const quote = source[index + prefix];
|
|
2808
|
+
const triple2 = source.startsWith(quote.repeat(3), index + prefix);
|
|
2809
|
+
let end;
|
|
2810
|
+
if (triple2) {
|
|
2811
|
+
const close = source.indexOf(quote.repeat(3), index + prefix + 3);
|
|
2812
|
+
end = close < 0 ? source.length : close + 3;
|
|
2813
|
+
} else end = scanQuoted(source, index + prefix, quote, !/[rR]/.test(source.slice(index, index + prefix)), false);
|
|
2814
|
+
pushToken(tokens, index, end, "string");
|
|
2815
|
+
index = end;
|
|
2816
|
+
pendingDef = void 0;
|
|
2817
|
+
continue;
|
|
2818
|
+
}
|
|
2819
|
+
IDENT.lastIndex = index;
|
|
2820
|
+
const identifier = IDENT.exec(source);
|
|
2821
|
+
if (identifier) {
|
|
2822
|
+
const word = identifier[0], end = index + word.length, folded = fold(word);
|
|
2823
|
+
let kind2;
|
|
2824
|
+
if (pendingDef && !keywords.has(folded)) kind2 = pendingDef;
|
|
2825
|
+
else if (keywords.has(folded)) {
|
|
2826
|
+
kind2 = "keyword";
|
|
2827
|
+
pendingDef = def.defs && Object.hasOwn(def.defs, folded) ? def.defs[folded] : void 0;
|
|
2828
|
+
pushToken(tokens, index, end, kind2);
|
|
2829
|
+
index = end;
|
|
2830
|
+
continue;
|
|
2831
|
+
} else if (literals.has(word) || literals.has(folded)) kind2 = "number";
|
|
2832
|
+
else if (types.has(folded)) kind2 = "type";
|
|
2833
|
+
else if (def.calls && source[end] === "(") kind2 = "function";
|
|
2834
|
+
else if (def.macros && source[end] === "!" && /[([{]/.test(source[end + 1] ?? "")) kind2 = "function";
|
|
2835
|
+
else if (def.capsTypes && /^[A-Z]/.test(word) && /[a-z]/.test(word)) kind2 = "type";
|
|
2836
|
+
pendingDef = void 0;
|
|
2837
|
+
if (kind2) pushToken(tokens, index, end, kind2);
|
|
2838
|
+
index = end;
|
|
2839
|
+
continue;
|
|
2840
|
+
}
|
|
2841
|
+
pendingDef = void 0;
|
|
2842
|
+
index++;
|
|
2843
|
+
}
|
|
2844
|
+
return tokens;
|
|
2845
|
+
}
|
|
2846
|
+
var YAML_LITERALS = /* @__PURE__ */ new Set(["true", "false", "null", "yes", "no", "on", "off", "~", "True", "False", "Null", "TRUE", "FALSE", "NULL"]);
|
|
2847
|
+
function scanYamlValue(source, start, end, tokens, comments) {
|
|
2848
|
+
let index = start;
|
|
2849
|
+
while (index < end) {
|
|
2850
|
+
const character = source[index];
|
|
2851
|
+
if (character === "#" && (index === start || /\s/.test(source[index - 1])) && comments.includes("#")) {
|
|
2852
|
+
pushToken(tokens, index, end, "comment");
|
|
2853
|
+
return;
|
|
2854
|
+
}
|
|
2855
|
+
if (character === ";" && comments.includes(";") && (index === start || /\s/.test(source[index - 1]))) {
|
|
2856
|
+
pushToken(tokens, index, end, "comment");
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
if (character === '"' || character === "'") {
|
|
2860
|
+
const close = scanQuoted(source, index, character, character === '"', false);
|
|
2861
|
+
pushToken(tokens, index, Math.min(close, end), "string");
|
|
2862
|
+
index = Math.min(close, end);
|
|
2863
|
+
continue;
|
|
2864
|
+
}
|
|
2865
|
+
if ((character === "&" || character === "*") && /[\w-]/.test(source[index + 1] ?? "")) {
|
|
2866
|
+
const match = /[&*][\w-]+/y;
|
|
2867
|
+
match.lastIndex = index;
|
|
2868
|
+
const found2 = match.exec(source);
|
|
2869
|
+
pushToken(tokens, index, index + found2[0].length, "type");
|
|
2870
|
+
index += found2[0].length;
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2873
|
+
if (!isIdentChar(source[index - 1]) && /[\d-]/.test(character)) {
|
|
2874
|
+
const match = /-?\d[\d_]*(?:\.\d+)?(?:[eE][+-]?\d+)?(?=[\s,\]}]|$)/y;
|
|
2875
|
+
match.lastIndex = index;
|
|
2876
|
+
const found2 = match.exec(source);
|
|
2877
|
+
if (found2 && index + found2[0].length <= end) {
|
|
2878
|
+
pushToken(tokens, index, index + found2[0].length, "number");
|
|
2879
|
+
index += found2[0].length;
|
|
2880
|
+
continue;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
const word = /[\w.~-]+/y;
|
|
2884
|
+
word.lastIndex = index;
|
|
2885
|
+
const found = word.exec(source);
|
|
2886
|
+
if (found) {
|
|
2887
|
+
if (YAML_LITERALS.has(found[0]) && !/[\w.-]/.test(source[index + found[0].length] ?? "")) pushToken(tokens, index, index + found[0].length, "number");
|
|
2888
|
+
index += found[0].length;
|
|
2889
|
+
continue;
|
|
2890
|
+
}
|
|
2891
|
+
index++;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
function lineRanges(source) {
|
|
2895
|
+
const ranges = [];
|
|
2896
|
+
let cursor = 0;
|
|
2897
|
+
const pattern = /\r\n|\r|\n/g;
|
|
2898
|
+
for (let match = pattern.exec(source); match; match = pattern.exec(source)) {
|
|
2899
|
+
ranges.push({ start: cursor, end: match.index });
|
|
2900
|
+
cursor = match.index + match[0].length;
|
|
2901
|
+
}
|
|
2902
|
+
ranges.push({ start: cursor, end: source.length });
|
|
2903
|
+
return ranges;
|
|
2904
|
+
}
|
|
2905
|
+
function yamlKey(source, from, to) {
|
|
2906
|
+
const first = source[from];
|
|
2907
|
+
if (first === void 0 || from >= to) return void 0;
|
|
2908
|
+
let index = from;
|
|
2909
|
+
if (first === '"' || first === "'") {
|
|
2910
|
+
index = Math.min(scanQuoted(source, from, first, first === '"', false), to);
|
|
2911
|
+
let at3 = index;
|
|
2912
|
+
while (at3 < to && (source[at3] === " " || source[at3] === " ")) at3++;
|
|
2913
|
+
return source[index - 1] === first && source[at3] === ":" && (at3 + 1 >= to || /\s/.test(source[at3 + 1])) ? { nameEnd: index, colon: at3 } : void 0;
|
|
2914
|
+
}
|
|
2915
|
+
if (/[\s#:{}[\],&*!|>%@`]/.test(first) || first === "-" && /[\s#:]/.test(source[from + 1] ?? " ")) return void 0;
|
|
2916
|
+
for (; index < to; index++) {
|
|
2917
|
+
const character = source[index];
|
|
2918
|
+
if (character === "#" && /\s/.test(source[index - 1])) return void 0;
|
|
2919
|
+
if (character === ":" && (index + 1 >= to || /\s/.test(source[index + 1]))) {
|
|
2920
|
+
let nameEnd = index;
|
|
2921
|
+
while (nameEnd > from && /\s/.test(source[nameEnd - 1])) nameEnd--;
|
|
2922
|
+
return nameEnd > from ? { nameEnd, colon: index } : void 0;
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
return void 0;
|
|
2926
|
+
}
|
|
2927
|
+
function scanYaml(source) {
|
|
2928
|
+
const tokens = [];
|
|
2929
|
+
let blockIndent = -1;
|
|
2930
|
+
for (const { start, end } of lineRanges(source)) {
|
|
2931
|
+
const text2 = source.slice(start, end), indent = /^ */.exec(text2)[0].length;
|
|
2932
|
+
if (blockIndent >= 0) {
|
|
2933
|
+
if (text2.trim() === "" || indent > blockIndent) {
|
|
2934
|
+
if (text2.trim() !== "") pushToken(tokens, start + indent, end, "string");
|
|
2935
|
+
continue;
|
|
2936
|
+
}
|
|
2937
|
+
blockIndent = -1;
|
|
2938
|
+
}
|
|
2939
|
+
if (/^\s*#/.test(text2)) {
|
|
2940
|
+
pushToken(tokens, start + indent, end, "comment");
|
|
2941
|
+
continue;
|
|
2942
|
+
}
|
|
2943
|
+
if (/^(?:---|\.\.\.)(?:\s|$)/.test(text2)) {
|
|
2944
|
+
pushToken(tokens, start, start + 3, "keyword");
|
|
2945
|
+
scanYamlValue(source, start + 3, end, tokens, "#");
|
|
2946
|
+
continue;
|
|
2947
|
+
}
|
|
2948
|
+
let cursor = start + indent;
|
|
2949
|
+
const dash = /^(?:-\s+)+/.exec(text2.slice(indent));
|
|
2950
|
+
if (dash) cursor += dash[0].length;
|
|
2951
|
+
let valueStart = cursor;
|
|
2952
|
+
const key = yamlKey(source, cursor, end);
|
|
2953
|
+
if (key) {
|
|
2954
|
+
pushToken(tokens, cursor, key.nameEnd, "property");
|
|
2955
|
+
valueStart = key.colon + 1;
|
|
2956
|
+
}
|
|
2957
|
+
scanYamlValue(source, valueStart, end, tokens, "#");
|
|
2958
|
+
if (/(?:^|\s)[|>][+-]?\d?\s*(?:#.*)?$/.test(text2.slice(valueStart - start))) blockIndent = indent;
|
|
2959
|
+
}
|
|
2960
|
+
return tokens;
|
|
2961
|
+
}
|
|
2962
|
+
function scanIni(source, def) {
|
|
2963
|
+
const tokens = [], comments = (def.line ?? []).join("");
|
|
2964
|
+
for (const { start, end } of lineRanges(source)) {
|
|
2965
|
+
const text2 = source.slice(start, end), indent = /^\s*/.exec(text2)[0].length, first = text2[indent];
|
|
2966
|
+
if (first === void 0) continue;
|
|
2967
|
+
if (comments.includes(first)) {
|
|
2968
|
+
pushToken(tokens, start + indent, end, "comment");
|
|
2969
|
+
continue;
|
|
2970
|
+
}
|
|
2971
|
+
if (first === "[") {
|
|
2972
|
+
const close = text2.indexOf("]", indent);
|
|
2973
|
+
const stop = close < 0 ? end : start + close + 1;
|
|
2974
|
+
pushToken(tokens, start + indent, stop, "type");
|
|
2975
|
+
scanYamlValue(source, stop, end, tokens, comments);
|
|
2976
|
+
continue;
|
|
2977
|
+
}
|
|
2978
|
+
const key = /^("[^"\n]*"|'[^'\n]*'|[^\s=:#;"']+(?:\s+[^\s=:#;"']+)*)\s*[=:]/.exec(text2.slice(indent));
|
|
2979
|
+
let valueStart = start + indent;
|
|
2980
|
+
if (key) {
|
|
2981
|
+
pushToken(tokens, start + indent, start + indent + key[1].length, "property");
|
|
2982
|
+
valueStart = start + indent + key[0].length;
|
|
2983
|
+
}
|
|
2984
|
+
scanYamlValue(source, valueStart, end, tokens, comments);
|
|
2985
|
+
}
|
|
2986
|
+
return tokens;
|
|
2987
|
+
}
|
|
2988
|
+
function scanMarkup(source) {
|
|
2989
|
+
const tokens = [];
|
|
2990
|
+
let index = 0;
|
|
2991
|
+
while (index < source.length) {
|
|
2992
|
+
const open = source.indexOf("<", index);
|
|
2993
|
+
if (open < 0) break;
|
|
2994
|
+
if (source.startsWith("<!--", open)) {
|
|
2995
|
+
const close = source.indexOf("-->", open + 4);
|
|
2996
|
+
const end = close < 0 ? source.length : close + 3;
|
|
2997
|
+
pushToken(tokens, open, end, "comment");
|
|
2998
|
+
index = end;
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
if (source.startsWith("<![CDATA[", open)) {
|
|
3002
|
+
const close = source.indexOf("]]>", open);
|
|
3003
|
+
const end = close < 0 ? source.length : close + 3;
|
|
3004
|
+
pushToken(tokens, open, end, "string");
|
|
3005
|
+
index = end;
|
|
3006
|
+
continue;
|
|
3007
|
+
}
|
|
3008
|
+
const name = /<([/?!]?)([A-Za-z][\w:.-]*|DOCTYPE)?/y;
|
|
3009
|
+
name.lastIndex = open;
|
|
3010
|
+
const found = name.exec(source);
|
|
3011
|
+
if (!found || !found[2]) {
|
|
3012
|
+
index = open + 1;
|
|
3013
|
+
continue;
|
|
3014
|
+
}
|
|
3015
|
+
pushToken(tokens, open + 1, open + found[0].length, "keyword");
|
|
3016
|
+
index = open + found[0].length;
|
|
3017
|
+
while (index < source.length && source[index] !== ">") {
|
|
3018
|
+
const character = source[index];
|
|
3019
|
+
if (character === '"' || character === "'") {
|
|
3020
|
+
const close = source.indexOf(character, index + 1);
|
|
3021
|
+
const end = close < 0 ? source.length : close + 1;
|
|
3022
|
+
pushToken(tokens, index, end, "string");
|
|
3023
|
+
index = end;
|
|
3024
|
+
continue;
|
|
3025
|
+
}
|
|
3026
|
+
const attribute = /[A-Za-z_:@#][\w:.@#-]*/y;
|
|
3027
|
+
attribute.lastIndex = index;
|
|
3028
|
+
const matched = attribute.exec(source);
|
|
3029
|
+
if (matched) {
|
|
3030
|
+
pushToken(tokens, index, index + matched[0].length, "property");
|
|
3031
|
+
index += matched[0].length;
|
|
3032
|
+
continue;
|
|
3033
|
+
}
|
|
3034
|
+
index++;
|
|
3035
|
+
}
|
|
3036
|
+
if (source[index] === ">") index++;
|
|
3037
|
+
}
|
|
3038
|
+
return tokens;
|
|
3039
|
+
}
|
|
3040
|
+
function scanCss(source) {
|
|
3041
|
+
const tokens = [];
|
|
3042
|
+
let index = 0, depth = 0;
|
|
3043
|
+
while (index < source.length) {
|
|
3044
|
+
const character = source[index];
|
|
3045
|
+
if (/\s/.test(character)) {
|
|
3046
|
+
index++;
|
|
3047
|
+
continue;
|
|
3048
|
+
}
|
|
3049
|
+
if (source.startsWith("/*", index)) {
|
|
3050
|
+
const close = source.indexOf("*/", index + 2);
|
|
3051
|
+
const end = close < 0 ? source.length : close + 2;
|
|
3052
|
+
pushToken(tokens, index, end, "comment");
|
|
3053
|
+
index = end;
|
|
3054
|
+
continue;
|
|
3055
|
+
}
|
|
3056
|
+
if (character === '"' || character === "'") {
|
|
3057
|
+
const end = scanQuoted(source, index, character, true, false);
|
|
3058
|
+
pushToken(tokens, index, end, "string");
|
|
3059
|
+
index = end;
|
|
3060
|
+
continue;
|
|
3061
|
+
}
|
|
3062
|
+
if (character === "{") {
|
|
3063
|
+
depth++;
|
|
3064
|
+
index++;
|
|
3065
|
+
continue;
|
|
3066
|
+
}
|
|
3067
|
+
if (character === "}") {
|
|
3068
|
+
depth = Math.max(0, depth - 1);
|
|
3069
|
+
index++;
|
|
3070
|
+
continue;
|
|
3071
|
+
}
|
|
3072
|
+
if (character === "@") {
|
|
3073
|
+
const match = /@[\w-]+/y;
|
|
3074
|
+
match.lastIndex = index;
|
|
3075
|
+
const found2 = match.exec(source);
|
|
3076
|
+
if (found2) {
|
|
3077
|
+
pushToken(tokens, index, index + found2[0].length, "keyword");
|
|
3078
|
+
index += found2[0].length;
|
|
3079
|
+
continue;
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
if (character === "!") {
|
|
3083
|
+
const match = /!\s*important/y;
|
|
3084
|
+
match.lastIndex = index;
|
|
3085
|
+
const found2 = match.exec(source);
|
|
3086
|
+
if (found2) {
|
|
3087
|
+
pushToken(tokens, index, index + found2[0].length, "keyword");
|
|
3088
|
+
index += found2[0].length;
|
|
3089
|
+
continue;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
if (character === "#" && depth > 0) {
|
|
3093
|
+
const match = /#[\da-fA-F]{3,8}\b/y;
|
|
3094
|
+
match.lastIndex = index;
|
|
3095
|
+
const found2 = match.exec(source);
|
|
3096
|
+
if (found2) {
|
|
3097
|
+
pushToken(tokens, index, index + found2[0].length, "number");
|
|
3098
|
+
index += found2[0].length;
|
|
3099
|
+
continue;
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
if (depth > 0 && (/\d/.test(character) || (character === "-" || character === "." || character === "+") && /\d/.test(source[index + 1] ?? ""))) {
|
|
3103
|
+
const match = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?(?:%|[a-zA-Z]+)?/y;
|
|
3104
|
+
match.lastIndex = index;
|
|
3105
|
+
const found2 = match.exec(source);
|
|
3106
|
+
if (found2 && !isIdentChar(source[index - 1])) {
|
|
3107
|
+
pushToken(tokens, index, index + found2[0].length, "number");
|
|
3108
|
+
index += found2[0].length;
|
|
3109
|
+
continue;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
const word = /-?[\p{L}_][\p{L}\p{N}_-]*/uy;
|
|
3113
|
+
word.lastIndex = index;
|
|
3114
|
+
const found = word.exec(source);
|
|
3115
|
+
if (found) {
|
|
3116
|
+
const end = index + found[0].length;
|
|
3117
|
+
let back = index - 1;
|
|
3118
|
+
while (back >= 0 && /\s/.test(source[back])) back--;
|
|
3119
|
+
const before = back >= 0 ? source[back] : "";
|
|
3120
|
+
if (depth > 0 && /^\s*:(?!:)/.test(source.slice(end, end + 8)) && (before === "{" || before === ";" || before === "")) pushToken(tokens, index, end, "property");
|
|
3121
|
+
else if (source[end] === "(") pushToken(tokens, index, end, "function");
|
|
3122
|
+
index = end;
|
|
3123
|
+
continue;
|
|
3124
|
+
}
|
|
3125
|
+
if (depth === 0 && (character === "." || character === "#")) {
|
|
3126
|
+
const match = /[.#][\p{L}_-][\p{L}\p{N}_-]*/uy;
|
|
3127
|
+
match.lastIndex = index;
|
|
3128
|
+
const matched = match.exec(source);
|
|
3129
|
+
if (matched) {
|
|
3130
|
+
pushToken(tokens, index, index + matched[0].length, "type");
|
|
3131
|
+
index += matched[0].length;
|
|
3132
|
+
continue;
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
index++;
|
|
3136
|
+
}
|
|
3137
|
+
return tokens;
|
|
3138
|
+
}
|
|
3139
|
+
function tokenizeCode(source, language) {
|
|
3140
|
+
const id = resolveCodeLanguage(language);
|
|
3141
|
+
if (id === void 0 || typeof source !== "string" || source.length === 0 || source.length > CODE_HIGHLIGHT_MAX_LENGTH) return [];
|
|
3142
|
+
const def = LANGUAGES[id];
|
|
3143
|
+
let tokens;
|
|
3144
|
+
switch (def.kind) {
|
|
3145
|
+
case "yaml":
|
|
3146
|
+
tokens = scanYaml(source);
|
|
3147
|
+
break;
|
|
3148
|
+
case "ini":
|
|
3149
|
+
tokens = scanIni(source, def);
|
|
3150
|
+
break;
|
|
3151
|
+
case "markup":
|
|
3152
|
+
tokens = scanMarkup(source);
|
|
3153
|
+
break;
|
|
3154
|
+
case "css":
|
|
3155
|
+
tokens = scanCss(source);
|
|
3156
|
+
break;
|
|
3157
|
+
default:
|
|
3158
|
+
tokens = scanGeneric(source, def);
|
|
3159
|
+
}
|
|
3160
|
+
return tokens.filter((token) => token.end > token.start).sort((a, b) => a.start - b.start);
|
|
3161
|
+
}
|
|
3162
|
+
function codeLineRuns(tokens, start, end, source) {
|
|
3163
|
+
const runs = [];
|
|
3164
|
+
const push = (from, to, kind2) => {
|
|
3165
|
+
if (kind2 === void 0 || source === void 0 || !source.slice(from, to).includes(" ")) {
|
|
3166
|
+
runs.push(kind2 === void 0 ? { start: from, end: to } : { start: from, end: to, kind: kind2 });
|
|
3167
|
+
return;
|
|
3168
|
+
}
|
|
3169
|
+
let at3 = from;
|
|
3170
|
+
for (let index = from; index < to; index++) {
|
|
3171
|
+
if (source[index] !== " ") continue;
|
|
3172
|
+
if (index > at3) runs.push({ start: at3, end: index, kind: kind2 });
|
|
3173
|
+
runs.push({ start: index, end: index + 1 });
|
|
3174
|
+
at3 = index + 1;
|
|
3175
|
+
}
|
|
3176
|
+
if (at3 < to) runs.push({ start: at3, end: to, kind: kind2 });
|
|
3177
|
+
};
|
|
3178
|
+
let cursor = start;
|
|
3179
|
+
for (const token of tokens) {
|
|
3180
|
+
if (token.end <= start) continue;
|
|
3181
|
+
if (token.start >= end) break;
|
|
3182
|
+
const from = Math.max(token.start, start), to = Math.min(token.end, end);
|
|
3183
|
+
if (from > cursor) push(cursor, from);
|
|
3184
|
+
push(from, to, token.kind);
|
|
3185
|
+
cursor = to;
|
|
3186
|
+
}
|
|
3187
|
+
if (cursor < end) push(cursor, end);
|
|
3188
|
+
return runs;
|
|
3189
|
+
}
|
|
3190
|
+
var distance = (a, b) => Math.hypot(...channels(a).map((value, index) => value - channels(b)[index]));
|
|
3191
|
+
var FALLBACK = { keyword: "#C4B5FD", string: "#86EFAC", number: "#FCD34D", function: "#93C5FD", type: "#67E8F9", property: "#F9A8D4", comment: "#94A3B8" };
|
|
3192
|
+
function codeSyntaxPalette(theme = {}, options = {}) {
|
|
3193
|
+
const background = normalize(options.background) ?? CODE_PANEL_BACKGROUND, plain = normalize(options.foreground) ?? CODE_PANEL_FOREGROUND;
|
|
3194
|
+
const minimum = options.minimumContrast ?? CODE_SYNTAX_MIN_CONTRAST;
|
|
3195
|
+
const palette = { plain: legible(plain, background, minimum) };
|
|
3196
|
+
const taken = [palette.plain];
|
|
3197
|
+
const slots = [["keyword", theme.primary], ["string", theme.accent], ["number", theme.secondary], ["comment", theme.mutedText], ["function", void 0], ["type", void 0], ["property", void 0]];
|
|
3198
|
+
for (const [kind2, themed] of slots) {
|
|
3199
|
+
const candidates = [normalize(themed), FALLBACK[kind2]].filter((value) => value !== void 0).map((value) => legible(value, background, minimum));
|
|
3200
|
+
let [h, s, l] = toHsl(FALLBACK[kind2]);
|
|
3201
|
+
let pick = candidates.find((candidate) => taken.every((other) => distance(candidate, other) >= 48));
|
|
3202
|
+
for (let turn = 0; pick === void 0 && turn < 9; turn++) {
|
|
3203
|
+
h += 40;
|
|
3204
|
+
const candidate = legible(fromHsl(h, s, l), background, minimum);
|
|
3205
|
+
if (taken.every((other) => distance(candidate, other) >= 48)) pick = candidate;
|
|
3206
|
+
}
|
|
3207
|
+
palette[kind2] = pick ?? candidates[candidates.length - 1];
|
|
3208
|
+
taken.push(palette[kind2]);
|
|
3209
|
+
}
|
|
3210
|
+
return palette;
|
|
3211
|
+
}
|
|
3212
|
+
function codeSyntaxPaletteForScheme(scheme, options = {}) {
|
|
3213
|
+
const record6 = scheme && typeof scheme === "object" ? scheme : {};
|
|
3214
|
+
const pick = (role, slot, fallback) => normalize(record6[role]) ?? normalize(record6[slot]) ?? fallback;
|
|
3215
|
+
return codeSyntaxPalette({ primary: pick("primary", "accent1", "#2563EB"), secondary: pick("secondary", "accent2", "#0F766E"), accent: pick("accent", "accent3", "#F59E0B") }, options);
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
// src/metric-trend.ts
|
|
3219
|
+
var METRIC_DEFAULT_SENTIMENT = Object.freeze({ up: "positive", down: "negative", flat: "neutral" });
|
|
3220
|
+
function metricEffectiveSentiment(trend, sentiment) {
|
|
3221
|
+
return sentiment ?? METRIC_DEFAULT_SENTIMENT[trend];
|
|
3222
|
+
}
|
|
3223
|
+
var METRIC_TREND_SHAPES = Object.freeze({ up: "upArrow", down: "downArrow", flat: "rightArrow" });
|
|
3224
|
+
var METRIC_TREND_MIN_CONTRAST = 4.5;
|
|
3225
|
+
var SEMANTIC = {
|
|
3226
|
+
positive: { light: "#15803D", dark: "#4ADE80" },
|
|
3227
|
+
negative: { light: "#B91C1C", dark: "#F87171" }
|
|
3228
|
+
};
|
|
3229
|
+
function metricTrendColor(trend, options) {
|
|
3230
|
+
const background = normalize(options.background) ?? "#FFFFFF";
|
|
3231
|
+
const sentiment = metricEffectiveSentiment(trend, options.sentiment);
|
|
3232
|
+
if (sentiment === "neutral") return legible(normalize(options.neutral) ?? (luminance2(background) < 0.5 ? "#CBD5E1" : "#475569"), background, METRIC_TREND_MIN_CONTRAST);
|
|
3233
|
+
const pair = SEMANTIC[sentiment];
|
|
3234
|
+
return legible(luminance2(background) < 0.5 ? pair.dark : pair.light, background, METRIC_TREND_MIN_CONTRAST);
|
|
3235
|
+
}
|
|
3236
|
+
function metricTrendPoints(shape, box) {
|
|
3237
|
+
const { x: l, y: t, width: w, height: h } = box, r = l + w, b = t + h, hc = l + w / 2, vc = t + h / 2, ss = Math.min(w, h);
|
|
3238
|
+
if (shape === "rightArrow") {
|
|
3239
|
+
const x12 = r - ss * 0.5, y1 = vc - h * 0.25, y22 = vc + h * 0.25;
|
|
3240
|
+
return [[l, y1], [x12, y1], [x12, t], [r, vc], [x12, b], [x12, y22], [l, y22]];
|
|
3241
|
+
}
|
|
3242
|
+
const dy = ss * 0.5, x1 = hc - w * 0.25, x2 = hc + w * 0.25;
|
|
3243
|
+
if (shape === "upArrow") {
|
|
3244
|
+
const y22 = t + dy;
|
|
3245
|
+
return [[l, y22], [hc, t], [r, y22], [x2, y22], [x2, b], [x1, b], [x1, y22]];
|
|
3246
|
+
}
|
|
3247
|
+
const y2 = b - dy;
|
|
3248
|
+
return [[l, y2], [x1, y2], [x1, t], [x2, t], [x2, y2], [r, y2], [hc, b]];
|
|
3249
|
+
}
|
|
3250
|
+
function metricTrendMark(layout, options) {
|
|
3251
|
+
const part = layout.parts.find((candidate) => candidate.role === "trend");
|
|
3252
|
+
if (!part || !part.visible || !part.fit || part.fit.sourceLines.length === 0) return void 0;
|
|
3253
|
+
const trend = part.text.trim();
|
|
3254
|
+
if (!Object.hasOwn(METRIC_TREND_SHAPES, trend)) return void 0;
|
|
3255
|
+
const line = part.fit.sourceLines[0], origin = part.linePositions[0];
|
|
3256
|
+
if (!origin || line.width <= 0) return void 0;
|
|
3257
|
+
const size = part.fit.fontSize * 0.72, gap = part.fit.fontSize * 0.3, left = part.box.x, right = part.box.x + part.box.width;
|
|
3258
|
+
const after = origin.x + line.width + gap, before = origin.x - gap - size;
|
|
3259
|
+
const fitsAfter = after + size <= right + 0.01, fitsBefore = before >= left - 0.01;
|
|
3260
|
+
const x = layout.alignment === "left" ? fitsAfter ? after : fitsBefore ? before : void 0 : fitsBefore ? before : fitsAfter ? after : void 0;
|
|
3261
|
+
if (x === void 0) return void 0;
|
|
3262
|
+
const shape = METRIC_TREND_SHAPES[trend], box = { x, y: origin.baseline - size, width: size, height: size };
|
|
3263
|
+
const sentiment = metricEffectiveSentiment(trend, options.sentiment ?? layout.sentiment);
|
|
3264
|
+
return { trend, sentiment, shape, box, points: metricTrendPoints(shape, box), color: metricTrendColor(trend, { ...options, sentiment }), ariaLabel: `Trend: ${trend}`, path: part.path };
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
// src/timeline-status.ts
|
|
3268
|
+
var TIMELINE_STATUSES = Object.freeze(["done", "current", "planned"]);
|
|
3269
|
+
var TIMELINE_TEXT_MIN_CONTRAST = 4.5;
|
|
3270
|
+
var TIMELINE_OUTLINE_MIN_CONTRAST = 3;
|
|
3271
|
+
function timelineMarkerShapes(marker, colors) {
|
|
3272
|
+
const background = normalize(colors.background) ?? "#FFFFFF";
|
|
3273
|
+
const primary = normalize(colors.primary), outline = primary ? legible(primary, background, TIMELINE_OUTLINE_MIN_CONTRAST) : colors.primary;
|
|
3274
|
+
const shapes = [];
|
|
3275
|
+
const width = marker.strokeWidth ?? 0;
|
|
3276
|
+
if (marker.status === "current" && marker.ring) {
|
|
3277
|
+
shapes.push({ role: "ring", shape: "ellipse", cx: marker.x, cy: marker.y, radius: marker.ring.radius, fill: colors.background, stroke: { color: outline, width } });
|
|
3278
|
+
}
|
|
3279
|
+
if (marker.status === "planned") {
|
|
3280
|
+
shapes.push({ role: "marker", shape: "ellipse", cx: marker.x, cy: marker.y, radius: marker.radius, fill: colors.background, stroke: { color: outline, width } });
|
|
3281
|
+
} else {
|
|
3282
|
+
shapes.push({ role: "marker", shape: "ellipse", cx: marker.x, cy: marker.y, radius: marker.radius, fill: colors.primary });
|
|
3283
|
+
}
|
|
3284
|
+
return shapes;
|
|
3285
|
+
}
|
|
3286
|
+
function timelineTextColor(part, colors) {
|
|
3287
|
+
if (part.status !== "planned") return colors.text;
|
|
3288
|
+
const background = normalize(colors.background) ?? "#FFFFFF", muted = normalize(colors.mutedText);
|
|
3289
|
+
return muted ? legible(muted, background, TIMELINE_TEXT_MIN_CONTRAST) : colors.mutedText;
|
|
3290
|
+
}
|
|
3291
|
+
|
|
3292
|
+
// src/code-highlight.ts
|
|
3293
|
+
function codeLineCount(source) {
|
|
3294
|
+
let count = 1;
|
|
3295
|
+
for (let index = 0; index < source.length; index++) {
|
|
3296
|
+
const char = source[index];
|
|
3297
|
+
if (char === "\r" && source[index + 1] === "\n") index++;
|
|
3298
|
+
if (char === "\r" || char === "\n") count++;
|
|
3299
|
+
}
|
|
3300
|
+
return count > 1 && /(?:\r\n|\r|\n)$/.test(source) ? count - 1 : count;
|
|
3301
|
+
}
|
|
3302
|
+
var isLine = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
3303
|
+
function codeHighlightLines(highlight, source) {
|
|
3304
|
+
const lineCount = codeLineCount(source), marked = /* @__PURE__ */ new Set(), issues = [];
|
|
3305
|
+
if (!Array.isArray(highlight)) return { lineCount, lines: [], issues };
|
|
3306
|
+
highlight.forEach((entry, index) => {
|
|
3307
|
+
const range = Array.isArray(entry) ? entry : [entry, entry];
|
|
3308
|
+
if (range.length !== 2 || !isLine(range[0]) || !isLine(range[1])) {
|
|
3309
|
+
issues.push({ code: "code-highlight-invalid", index, message: "A code highlight entry is a line number or a [start, end] pair of line numbers from 1." });
|
|
3310
|
+
return;
|
|
3311
|
+
}
|
|
3312
|
+
const [start, end] = range;
|
|
3313
|
+
if (start > end) {
|
|
3314
|
+
issues.push({ code: "code-highlight-range-reversed", index, message: `The highlight range [${start}, ${end}] ends before it starts, so it marks no line; write [${end}, ${start}].` });
|
|
3315
|
+
return;
|
|
3316
|
+
}
|
|
3317
|
+
if (end > lineCount) issues.push({ code: "code-highlight-out-of-range", index, message: `The highlight ${start === end ? `line ${start}` : `range [${start}, ${end}]`} is past the last line (the code has ${lineCount} ${lineCount === 1 ? "line" : "lines"}); lines beyond it are ignored.` });
|
|
3318
|
+
for (let line = start; line <= Math.min(end, lineCount); line++) marked.add(line);
|
|
3319
|
+
});
|
|
3320
|
+
return { lineCount, lines: [...marked].sort((a, b) => a - b), issues };
|
|
3321
|
+
}
|
|
3322
|
+
function codeHighlightList(lines) {
|
|
3323
|
+
const sorted = [...new Set(lines)].sort((a, b) => a - b), out = [];
|
|
3324
|
+
for (let index = 0; index < sorted.length; ) {
|
|
3325
|
+
let end = index;
|
|
3326
|
+
while (sorted[end + 1] === sorted[end] + 1) end++;
|
|
3327
|
+
out.push(end === index ? sorted[index] : [sorted[index], sorted[end]]);
|
|
3328
|
+
index = end + 1;
|
|
3329
|
+
}
|
|
3330
|
+
return out;
|
|
3331
|
+
}
|
|
3332
|
+
function codeLineNumbers(sourceLines) {
|
|
3333
|
+
let line = 1;
|
|
3334
|
+
return sourceLines.map((entry) => {
|
|
3335
|
+
const number = line;
|
|
3336
|
+
if (entry.boundary === "hard") line++;
|
|
3337
|
+
return number;
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
function codeHighlightBands(sourceLines, lines) {
|
|
3341
|
+
if (!lines.length) return [];
|
|
3342
|
+
const marked = new Set(lines), numbers = codeLineNumbers(sourceLines), bands = [];
|
|
3343
|
+
numbers.forEach((number, index) => {
|
|
3344
|
+
if (!marked.has(number)) return;
|
|
3345
|
+
const last = bands.at(-1);
|
|
3346
|
+
if (last && last.last === index - 1) last.last = index;
|
|
3347
|
+
else bands.push({ first: index, last: index });
|
|
3348
|
+
});
|
|
3349
|
+
return bands;
|
|
3350
|
+
}
|
|
3351
|
+
function codeHighlightSlice(highlight, source, start, end) {
|
|
3352
|
+
const { lines } = codeHighlightLines(highlight, source);
|
|
3353
|
+
if (!lines.length) return void 0;
|
|
3354
|
+
const breaks = (text2) => (text2.match(/\r\n|\r|\n/g) ?? []).length;
|
|
3355
|
+
const before = breaks(source.slice(0, start)), count = codeLineCount(source.slice(start, end));
|
|
3356
|
+
const kept = lines.filter((line) => line > before && line <= before + count).map((line) => line - before);
|
|
3357
|
+
return kept.length ? codeHighlightList(kept) : void 0;
|
|
3358
|
+
}
|
|
3359
|
+
var CODE_HIGHLIGHT_DIM = 0.35;
|
|
3360
|
+
var CODE_HIGHLIGHT_BAND_TINT = 0.3;
|
|
3361
|
+
var blend = (from, to, amount) => {
|
|
3362
|
+
const a = channels(from), b = channels(to);
|
|
3363
|
+
return toHex(a.map((value, index) => value + (b[index] - value) * amount));
|
|
3364
|
+
};
|
|
3365
|
+
function codeHighlightColors(scheme, palette = codeSyntaxPaletteForScheme(scheme)) {
|
|
3366
|
+
const record6 = scheme && typeof scheme === "object" ? scheme : {};
|
|
3367
|
+
const primary = normalize(record6.primary) ?? normalize(record6.accent1) ?? "#2563EB";
|
|
3368
|
+
const [hue, saturation] = toHsl(primary);
|
|
3369
|
+
const tint = fromHsl(hue, Math.min(saturation, 0.7), 0.45);
|
|
3370
|
+
const band = blend(CODE_PANEL_BACKGROUND, tint, CODE_HIGHLIGHT_BAND_TINT);
|
|
3371
|
+
const lit = {}, dim = {};
|
|
3372
|
+
for (const key of Object.keys(palette)) {
|
|
3373
|
+
lit[key] = legible(palette[key], band, CODE_SYNTAX_MIN_CONTRAST);
|
|
3374
|
+
dim[key] = legible(blend(palette[key], CODE_PANEL_BACKGROUND, CODE_HIGHLIGHT_DIM), CODE_PANEL_BACKGROUND, CODE_SYNTAX_MIN_CONTRAST);
|
|
3375
|
+
}
|
|
3376
|
+
return { band, lit, dim };
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
// src/watermark.ts
|
|
3380
|
+
var WATERMARK_TEXT_ROTATION = -30;
|
|
3381
|
+
var WATERMARK_TEXT_MAX_WIDTH = 0.7;
|
|
3382
|
+
var WATERMARK_TEXT_MAX_HEIGHT = 0.3;
|
|
3383
|
+
function layoutWatermark(text2, size, options = {}) {
|
|
3384
|
+
const value = typeof text2 === "string" ? text2.replace(/\s*[\r\n]+\s*/g, " ").trim() : "";
|
|
3385
|
+
if (!value) return void 0;
|
|
3386
|
+
const { width, height } = size;
|
|
3387
|
+
if (![width, height].every((n) => Number.isFinite(n) && n > 0)) throw new RangeError("Watermark slide size must be finite and positive.");
|
|
3388
|
+
const fontFamily = options.fontFamily ?? "sans-serif", fontWeight = options.fontWeight ?? 700;
|
|
3389
|
+
const style = resolveTextStyle({ fontFamily, fontWeight, italic: false, path: "design.watermark" }, options.textMeasurement);
|
|
3390
|
+
const measure = textWidthMeasurer(style, options.textMeasurement);
|
|
3391
|
+
const reference = 100, unit = measure(value, reference);
|
|
3392
|
+
const wanted = unit > 0 ? WATERMARK_TEXT_MAX_WIDTH * width * reference / unit : WATERMARK_TEXT_MAX_HEIGHT * Math.min(width, height);
|
|
3393
|
+
const fontSize = Math.max(1, Math.min(wanted, WATERMARK_TEXT_MAX_HEIGHT * Math.min(width, height)));
|
|
3394
|
+
const textWidth = measure(value, fontSize);
|
|
3395
|
+
const boxWidth = textWidth + fontSize * 0.5, boxHeight = fontSize * 1.4;
|
|
3396
|
+
return {
|
|
3397
|
+
text: value,
|
|
3398
|
+
fontFamily: style.fontFamily,
|
|
3399
|
+
fontWeight,
|
|
3400
|
+
style,
|
|
3401
|
+
fontSize,
|
|
3402
|
+
textWidth,
|
|
3403
|
+
box: { x: (width - boxWidth) / 2, y: (height - boxHeight) / 2, width: boxWidth, height: boxHeight },
|
|
3404
|
+
rotation: WATERMARK_TEXT_ROTATION
|
|
3405
|
+
};
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
// src/pattern-fills.ts
|
|
3409
|
+
var PATTERN_PRESETS = Object.freeze([
|
|
3410
|
+
"pct5",
|
|
3411
|
+
"pct10",
|
|
3412
|
+
"pct20",
|
|
3413
|
+
"pct25",
|
|
3414
|
+
"pct30",
|
|
3415
|
+
"pct40",
|
|
3416
|
+
"pct50",
|
|
3417
|
+
"pct60",
|
|
3418
|
+
"pct70",
|
|
3419
|
+
"pct75",
|
|
3420
|
+
"pct80",
|
|
3421
|
+
"pct90",
|
|
3422
|
+
"horz",
|
|
3423
|
+
"vert",
|
|
3424
|
+
"ltHorz",
|
|
3425
|
+
"ltVert",
|
|
3426
|
+
"dkHorz",
|
|
3427
|
+
"dkVert",
|
|
3428
|
+
"narHorz",
|
|
3429
|
+
"narVert",
|
|
3430
|
+
"dashHorz",
|
|
3431
|
+
"dashVert",
|
|
3432
|
+
"cross",
|
|
3433
|
+
"dnDiag",
|
|
3434
|
+
"upDiag",
|
|
3435
|
+
"ltDnDiag",
|
|
3436
|
+
"ltUpDiag",
|
|
3437
|
+
"dkDnDiag",
|
|
3438
|
+
"dkUpDiag",
|
|
3439
|
+
"wdDnDiag",
|
|
3440
|
+
"wdUpDiag",
|
|
3441
|
+
"dashDnDiag",
|
|
3442
|
+
"dashUpDiag",
|
|
3443
|
+
"diagCross",
|
|
3444
|
+
"smCheck",
|
|
3445
|
+
"lgCheck",
|
|
3446
|
+
"smGrid",
|
|
3447
|
+
"lgGrid",
|
|
3448
|
+
"dotGrid",
|
|
3449
|
+
"smConfetti",
|
|
3450
|
+
"lgConfetti",
|
|
3451
|
+
"horzBrick",
|
|
3452
|
+
"diagBrick",
|
|
3453
|
+
"solidDmnd",
|
|
3454
|
+
"openDmnd",
|
|
3455
|
+
"dotDmnd",
|
|
3456
|
+
"plaid",
|
|
3457
|
+
"sphere",
|
|
3458
|
+
"weave",
|
|
3459
|
+
"divot",
|
|
3460
|
+
"shingle",
|
|
3461
|
+
"wave",
|
|
3462
|
+
"trellis",
|
|
3463
|
+
"zigZag"
|
|
3464
|
+
]);
|
|
3465
|
+
var PATTERN_PRESET_ALIASES = Object.freeze({ diagStripe: "wdUpDiag" });
|
|
3466
|
+
var PATTERN_TILE_SIZE = 8;
|
|
3467
|
+
var MEASURED = {
|
|
3468
|
+
pct5: "#......./......../......../......../....#.../......../......../........",
|
|
3469
|
+
pct10: "#......./......../....#.../......../#......./......../....#.../........",
|
|
3470
|
+
pct20: "#...#.../......../..#...#./......../#...#.../......../..#...#./........",
|
|
3471
|
+
pct25: "#...#.../..#...#./#...#.../..#...#./#...#.../..#...#./#...#.../..#...#.",
|
|
3472
|
+
pct30: "#.#.#.#./.#...#../#.#.#.#./...#...#/#.#.#.#./.#...#../#.#.#.#./...#...#",
|
|
3473
|
+
pct40: "#.#.#.#./.#.#.#.#/#.#.#.#./.#.#...#/#.#.#.#./.#.#.#.#/#.#.#.#./...#.#.#",
|
|
3474
|
+
pct50: "#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#",
|
|
3475
|
+
pct60: "###.###./.#.#.#.#/#.###.##/.#.#.#.#/###.###./.#.#.#.#/#.###.##/.#.#.#.#",
|
|
3476
|
+
pct70: ".###.###/##.###.#/.###.###/##.###.#/.###.###/##.###.#/.###.###/##.###.#",
|
|
3477
|
+
pct75: ".###.###/########/##.###.#/########/.###.###/########/##.###.#/########",
|
|
3478
|
+
pct80: "###.####/########/#######./########/###.####/########/#######./########",
|
|
3479
|
+
pct90: "########/########/########/####.###/########/########/########/.#######",
|
|
3480
|
+
horz: "########/......../......../......../......../......../......../........",
|
|
3481
|
+
vert: "#......./#......./#......./#......./#......./#......./#......./#.......",
|
|
3482
|
+
ltHorz: "########/......../......../......../########/......../......../........",
|
|
3483
|
+
ltVert: "#...#.../#...#.../#...#.../#...#.../#...#.../#...#.../#...#.../#...#...",
|
|
3484
|
+
dkHorz: "########/########/......../......../########/########/......../........",
|
|
3485
|
+
dkVert: "##..##../##..##../##..##../##..##../##..##../##..##../##..##../##..##..",
|
|
3486
|
+
narHorz: "########/......../########/......../########/......../########/........",
|
|
3487
|
+
narVert: ".#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#/.#.#.#.#",
|
|
3488
|
+
dashHorz: "####..../......../......../......../....####/......../......../........",
|
|
3489
|
+
dashVert: "#......./#......./#......./#......./....#.../....#.../....#.../....#...",
|
|
3490
|
+
cross: "########/#......./#......./#......./#......./#......./#......./#.......",
|
|
3491
|
+
dnDiag: "#......./.#....../..#...../...#..../....#.../.....#../......#./.......#",
|
|
3492
|
+
upDiag: ".......#/......#./.....#../....#.../...#..../..#...../.#....../#.......",
|
|
3493
|
+
ltDnDiag: "#...#.../.#...#../..#...#./...#...#/#...#.../.#...#../..#...#./...#...#",
|
|
3494
|
+
ltUpDiag: "...#...#/..#...#./.#...#../#...#.../...#...#/..#...#./.#...#../#...#...",
|
|
3495
|
+
dkDnDiag: "##..##../.##..##./..##..##/#..##..#/##..##../.##..##./..##..##/#..##..#",
|
|
3496
|
+
dkUpDiag: "..##..##/.##..##./##..##../#..##..#/..##..##/.##..##./##..##../#..##..#",
|
|
3497
|
+
wdDnDiag: "##.....#/###...../.###..../..###.../...###../....###./.....###/#.....##",
|
|
3498
|
+
wdUpDiag: "#.....##/.....###/....###./...###../..###.../.###..../###...../##.....#",
|
|
3499
|
+
dashDnDiag: "......../......../#...#.../.#...#../..#...#./...#...#/......../........",
|
|
3500
|
+
dashUpDiag: "......../......../...#...#/..#...#./.#...#../#...#.../......../........",
|
|
3501
|
+
diagCross: "#......#/.#....#./..#..#../...##.../...##.../..#..#../.#....#./#......#",
|
|
3502
|
+
smCheck: "#..##..#/.##..##./.##..##./#..##..#/#..##..#/.##..##./.##..##./#..##..#",
|
|
3503
|
+
lgCheck: "####..../####..../####..../####..../....####/....####/....####/....####",
|
|
3504
|
+
smGrid: "########/#...#.../#...#.../#...#.../########/#...#.../#...#.../#...#...",
|
|
3505
|
+
lgGrid: "########/#......./#......./#......./#......./#......./#......./#.......",
|
|
3506
|
+
dotGrid: "#.#.#.#./......../#......./......../#......./......../#......./........",
|
|
3507
|
+
smConfetti: "#......./....#.../.#....../......#./...#..../.......#/..#...../.....#..",
|
|
3508
|
+
lgConfetti: "#.##...#/..##..../......##/...##.##/##.##.../##....../....##../#...##.#",
|
|
3509
|
+
horzBrick: "########/#......./#......./#......./########/....#.../....#.../....#...",
|
|
3510
|
+
diagBrick: ".......#/......#./.....#../....#.../...##.../..#..#../.#....#./#......#",
|
|
3511
|
+
solidDmnd: "...#..../..###.../.#####../#######./.#####../..###.../...#..../........",
|
|
3512
|
+
openDmnd: "#.....#./.#...#../..#.#.../...#..../..#.#.../.#...#../#.....#./.......#",
|
|
3513
|
+
dotDmnd: "#......./......../..#...#./......../....#.../......../..#...#./........",
|
|
3514
|
+
plaid: "#.#.#.#./.#.#.#.#/#.#.#.#./.#.#.#.#/####..../####..../####..../####....",
|
|
3515
|
+
sphere: ".###.###/#...#..#/#...####/#...####/.###.###/#..##.../#####.../#####...",
|
|
3516
|
+
weave: "#...#.../.#.#.#../..#...#./.#...#.#/#...#.../...#.#../..#...#./.#.#...#",
|
|
3517
|
+
divot: "......../...#..../....#.../...#..../......../#......./.......#/#.......",
|
|
3518
|
+
shingle: "......##/#....#../.#..#.../..##..../....##../......#./.......#/.......#",
|
|
3519
|
+
wave: "......../...##.../..#..#.#/##....../......../...##.../..#..#.#/##......",
|
|
3520
|
+
trellis: "########/.##..##./########/#..##..#/########/.##..##./########/#..##..#",
|
|
3521
|
+
zigZag: "#......#/.#....#./..#..#../...##.../#......#/.#....#./..#..#../...##..."
|
|
3522
|
+
};
|
|
3523
|
+
function rows(preset) {
|
|
3524
|
+
const art = MEASURED[preset];
|
|
3525
|
+
if (!art) return void 0;
|
|
3526
|
+
return art.split("/").map((row) => [...row].reduce((bits, cell, index) => cell === "#" ? bits | 128 >> index : bits, 0));
|
|
3527
|
+
}
|
|
3528
|
+
var BITMAPS = /* @__PURE__ */ new Map();
|
|
3529
|
+
for (const preset of PATTERN_PRESETS) {
|
|
3530
|
+
const bitmap = rows(preset);
|
|
3531
|
+
if (bitmap) BITMAPS.set(preset, Object.freeze(bitmap));
|
|
3532
|
+
}
|
|
3533
|
+
function resolvePatternPreset(preset) {
|
|
3534
|
+
if (typeof preset !== "string") return void 0;
|
|
3535
|
+
if (BITMAPS.has(preset)) return preset;
|
|
3536
|
+
return Object.hasOwn(PATTERN_PRESET_ALIASES, preset) ? PATTERN_PRESET_ALIASES[preset] : void 0;
|
|
3537
|
+
}
|
|
3538
|
+
function patternBitmap(preset) {
|
|
3539
|
+
const resolved = resolvePatternPreset(preset);
|
|
3540
|
+
return resolved === void 0 ? void 0 : BITMAPS.get(resolved);
|
|
3541
|
+
}
|
|
3542
|
+
function patternRuns(preset) {
|
|
3543
|
+
const bitmap = patternBitmap(preset);
|
|
3544
|
+
if (!bitmap) return void 0;
|
|
3545
|
+
const runs = [];
|
|
3546
|
+
bitmap.forEach((row, y) => {
|
|
3547
|
+
for (let x = 0; x < 8; x++) {
|
|
3548
|
+
if (!(row & 128 >> x)) continue;
|
|
3549
|
+
const start = x;
|
|
3550
|
+
while (x + 1 < 8 && row & 128 >> x + 1) x++;
|
|
3551
|
+
runs.push({ x: start, y, width: x - start + 1 });
|
|
3552
|
+
}
|
|
3553
|
+
});
|
|
3554
|
+
return runs;
|
|
3555
|
+
}
|
|
2666
3556
|
|
|
2667
3557
|
// src/annotations.ts
|
|
2668
3558
|
var CITATION_MARKER_SCALE = 2 / 3;
|
|
@@ -2676,6 +3566,7 @@ var isRecord3 = (value) => !!value && typeof value === "object" && !Array.isArra
|
|
|
2676
3566
|
var round = (value) => Math.round(value * 1e6) / 1e6 || value;
|
|
2677
3567
|
var regionKey = /^(top|middle|bottom|left|center|right)([+:]|$)/;
|
|
2678
3568
|
var TEXT_FIELDS = ["text", "items", "bullets"];
|
|
3569
|
+
var HEADING_FIELDS = ["tag", "title", "subtitle"];
|
|
2679
3570
|
function annotationText(value) {
|
|
2680
3571
|
if (typeof value === "string") return value;
|
|
2681
3572
|
if (Array.isArray(value)) return value.map((run) => typeof run === "string" ? run : record4(run).text ?? "").join("");
|
|
@@ -2723,8 +3614,10 @@ function walkCitationRuns(slide, basePath, visit) {
|
|
|
2723
3614
|
if (field === "text") runs(payload.text, `${path}.text`);
|
|
2724
3615
|
else list(payload[field], `${path}.${field}`);
|
|
2725
3616
|
}
|
|
3617
|
+
if (isRecord3(payload.quote)) runs(payload.quote.text, `${path}.quote.text`);
|
|
2726
3618
|
};
|
|
2727
3619
|
const value = record4(slide);
|
|
3620
|
+
for (const field of HEADING_FIELDS) runs(value[field], `${basePath}.${field}`);
|
|
2728
3621
|
const regions = Object.keys(value).filter((key) => regionKey.test(key)).sort();
|
|
2729
3622
|
if (regions.length) {
|
|
2730
3623
|
for (const key of regions) host(value[key], `${basePath}.${key}`, 0);
|
|
@@ -2846,6 +3739,29 @@ function referencesSlide(presentation, options = {}) {
|
|
|
2846
3739
|
return { title, items };
|
|
2847
3740
|
}
|
|
2848
3741
|
|
|
3742
|
+
// src/layout-content.ts
|
|
3743
|
+
var LAYOUT_BODY_KINDS = ["text", "list", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
|
|
3744
|
+
var bodyKinds = new Set(LAYOUT_BODY_KINDS);
|
|
3745
|
+
function layoutContent(record6) {
|
|
3746
|
+
const heading = { title: false, subtitle: false, tag: false };
|
|
3747
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3748
|
+
let count = 0;
|
|
3749
|
+
for (const placeholder of Array.isArray(record6?.placeholders) ? record6.placeholders : []) {
|
|
3750
|
+
const type = placeholder?.type;
|
|
3751
|
+
if (type === "title" || type === "subtitle" || type === "tag") heading[type] = true;
|
|
3752
|
+
else if (typeof type === "string" && bodyKinds.has(type)) {
|
|
3753
|
+
counts.set(type, (counts.get(type) ?? 0) + 1);
|
|
3754
|
+
count += 1;
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
let kind2 = "title", best = 0;
|
|
3758
|
+
for (const [candidate, total] of counts) if (total > best) {
|
|
3759
|
+
kind2 = candidate;
|
|
3760
|
+
best = total;
|
|
3761
|
+
}
|
|
3762
|
+
return { kind: kind2, count, heading };
|
|
3763
|
+
}
|
|
3764
|
+
|
|
2849
3765
|
// src/composition.ts
|
|
2850
3766
|
var MAX_COMPOSITION_DEPTH = 32;
|
|
2851
3767
|
var FALLBACK_CODE_FAMILY = "Roboto Mono";
|
|
@@ -2862,7 +3778,7 @@ function resolveFontSchemeReference(reference, lookup, path = "design.fontScheme
|
|
|
2862
3778
|
}
|
|
2863
3779
|
function resolveFontFamilies(input) {
|
|
2864
3780
|
const scheme = record5(input);
|
|
2865
|
-
const family = (value) => typeof value === "string" ? value :
|
|
3781
|
+
const family = (value) => typeof value === "string" && value ? value : void 0;
|
|
2866
3782
|
const accent = family(scheme.accent);
|
|
2867
3783
|
return {
|
|
2868
3784
|
heading: family(scheme.heading) ?? scheme.major ?? scheme.minor ?? DEFAULT_FONT_FAMILIES.heading,
|
|
@@ -2946,7 +3862,7 @@ var OPFCompositionError = class extends Error {
|
|
|
2946
3862
|
var fields = ["text", "items", "bullets", "image", "video", "chart", "table", "code", "metric", "quote", "timeline"];
|
|
2947
3863
|
var headings = /* @__PURE__ */ new Set(["title", "subtitle", "tag"]);
|
|
2948
3864
|
var COVER_LAYOUT_IDS = /* @__PURE__ */ new Set(["title", "title-subtitle"]);
|
|
2949
|
-
var
|
|
3865
|
+
var rows2 = ["top", "middle", "bottom"];
|
|
2950
3866
|
var columns = ["left", "center", "right"];
|
|
2951
3867
|
var record5 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2952
3868
|
var kind = (field) => field === "items" ? "list" : field === "bullets" ? "text" : field;
|
|
@@ -2982,14 +3898,14 @@ function resolveSlideImage(slide, layout, presentation, width, height, path, pad
|
|
|
2982
3898
|
const configured = local ? own2.slideImage : deck.slideImage;
|
|
2983
3899
|
if (!configured || typeof configured !== "object" && typeof configured !== "string") return void 0;
|
|
2984
3900
|
const treatment = typeof configured === "object" && !Array.isArray(configured) && "position" in configured ? record5(configured) : void 0;
|
|
2985
|
-
const
|
|
2986
|
-
const authoredPosition = treatment ? treatment.position : SLIDE_IMAGE_POSITIONS.find((value2) => value2 ===
|
|
3901
|
+
const layoutImage = record5(record5(layout.design).slideImage), layoutPosition = layoutImage.position;
|
|
3902
|
+
const authoredPosition = treatment ? treatment.position : SLIDE_IMAGE_POSITIONS.find((value2) => value2 === layoutPosition) ?? "background";
|
|
2987
3903
|
if (!SLIDE_IMAGE_POSITIONS.includes(authoredPosition)) return void 0;
|
|
2988
3904
|
const mirrorSide = (side) => !rtl ? side : side === "left" ? "right" : side === "right" ? "left" : side;
|
|
2989
3905
|
const position = mirrorSide(authoredPosition);
|
|
2990
3906
|
const designSource = treatment ? treatment.src : configured;
|
|
2991
3907
|
const root = slide.image, sameSource = root !== void 0 && designSource !== void 0 && assetSource(root) === assetSource(designSource);
|
|
2992
|
-
if (!local && layout.slideImage
|
|
3908
|
+
if (!local && record5(layout.design).slideImage === void 0 && !sameSource) return void 0;
|
|
2993
3909
|
const replacesContent = root !== void 0 && (designSource === void 0 || sameSource);
|
|
2994
3910
|
const value = replacesContent ? root : designSource;
|
|
2995
3911
|
const source = assetSource(value);
|
|
@@ -3058,10 +3974,10 @@ function resolveLogo(presentation, slide, options = {}) {
|
|
|
3058
3974
|
if (typeof value === "string" || typeof value === "object" && !Array.isArray(value) && "src" in record5(value)) {
|
|
3059
3975
|
return usable(value) ? { source: value, path, variant: "default", slot } : null;
|
|
3060
3976
|
}
|
|
3061
|
-
const
|
|
3062
|
-
if (!Object.keys(
|
|
3977
|
+
const set2 = record5(value);
|
|
3978
|
+
if (!Object.keys(set2).some((key) => LOGO_SET_KEYS.has(key))) return null;
|
|
3063
3979
|
for (const key of chain) {
|
|
3064
|
-
const variant =
|
|
3980
|
+
const variant = set2[key];
|
|
3065
3981
|
if (variant !== void 0 && usable(variant)) return { source: variant, path: `${path}.${key}`, variant: key, slot };
|
|
3066
3982
|
}
|
|
3067
3983
|
return null;
|
|
@@ -3108,8 +4024,9 @@ function layoutFurniture(input, options = {}) {
|
|
|
3108
4024
|
const sourceRoot = `slides.${options.slideIndex ?? 0}`, organizations = Array.isArray(options.presentation?.organization) ? options.presentation.organization : [options.presentation?.organization];
|
|
3109
4025
|
const primaryIndex = organizations.findIndex((item) => record5(item).role === "primary"), organizationIndex = primaryIndex >= 0 ? primaryIndex : organizations.findIndex(Boolean);
|
|
3110
4026
|
const organization = record5(organizations[organizationIndex]), organizationRoot = Array.isArray(options.presentation?.organization) ? `organization.${organizationIndex}` : "organization", organizationPath = `${organizationRoot}.name`;
|
|
4027
|
+
const speakers = Array.isArray(options.presentation?.speaker) ? options.presentation.speaker : [options.presentation?.speaker], speaker = record5(speakers[0]), speakerRoot = Array.isArray(options.presentation?.speaker) ? "speaker.0" : "speaker";
|
|
3111
4028
|
const inlinePlatforms = record5(record5(options.presentation?.catalogs).socialPlatforms).records, platformRecords = [...Array.isArray(inlinePlatforms) ? inlinePlatforms : [], ...options.socialPlatforms ?? []];
|
|
3112
|
-
const fontFamily = options.
|
|
4029
|
+
const fontFamily = options.fontFamilies?.body ?? "sans-serif";
|
|
3113
4030
|
let headerBottom = 0, footerTop = height, configured = false;
|
|
3114
4031
|
const error = (path, message, code = "text-overflow") => diagnostics.push({ code, path, message });
|
|
3115
4032
|
for (const kind2 of ["header", "footer"]) {
|
|
@@ -3179,6 +4096,10 @@ function layoutFurniture(input, options = {}) {
|
|
|
3179
4096
|
if (typeof organization.name === "string") add("organization", organization.name, true, organizationPath);
|
|
3180
4097
|
else error(`${path}.organization`, "Generated organization name needs a named organization in the presentation.", "unresolved-content");
|
|
3181
4098
|
}
|
|
4099
|
+
if (content.speaker === true) {
|
|
4100
|
+
if (typeof speaker.name === "string" && speaker.name.trim()) add("speaker", typeof speaker.title === "string" && speaker.title.trim() ? `${speaker.name}, ${speaker.title}` : speaker.name, true, `${speakerRoot}.name`);
|
|
4101
|
+
else error(`${path}.speaker`, "Generated speaker needs a named speaker in the presentation.", "unresolved-content");
|
|
4102
|
+
}
|
|
3182
4103
|
if (content.socials === true) {
|
|
3183
4104
|
const links = Object.entries(record5(organization.socials)).filter(([, value2]) => typeof value2 === "string" && value2.trim()).map(([platform, value2]) => ({ platform, sourcePath: `${organizationRoot}.socials.${platform}`, ...resolveSocialProfile(platform, value2, platformRecords, "organization") }));
|
|
3184
4105
|
if (links.length) add("socials", links.map((link) => link.text).join("\n"), true, `${organizationRoot}.socials`, { links });
|
|
@@ -3272,12 +4193,25 @@ function fitAtSizes(layout, requested, minimum, step = 1, snap = true) {
|
|
|
3272
4193
|
}
|
|
3273
4194
|
throw new Error("Text fitting did not evaluate its bounded floor trial.");
|
|
3274
4195
|
}
|
|
4196
|
+
var PHOTO_RATIO = 3;
|
|
4197
|
+
var PHOTO_GAP = 0.75;
|
|
4198
|
+
function quoteBodyRuns(runs) {
|
|
4199
|
+
if (!runs.length) return ['""'];
|
|
4200
|
+
const last = runs.length - 1;
|
|
4201
|
+
return runs.map((run, index) => {
|
|
4202
|
+
const before = index === 0 ? '"' : "", after = index === last ? '"' : "";
|
|
4203
|
+
return typeof run === "string" ? before + run + after : { ...run, text: before + run.text + after };
|
|
4204
|
+
});
|
|
4205
|
+
}
|
|
3275
4206
|
function layoutQuote(value, box, options = {}) {
|
|
3276
4207
|
const shorthand = typeof value === "string";
|
|
3277
4208
|
const quote = shorthand ? { text: value } : value;
|
|
3278
|
-
|
|
3279
|
-
|
|
4209
|
+
const photoValue = quote?.photo;
|
|
4210
|
+
if (!quote || Array.isArray(quote) || typeof quote.text !== "string" && !Array.isArray(quote.text) || [quote.attribution, quote.role, quote.source].some((field) => field !== void 0 && typeof field !== "string") || photoValue !== void 0 && typeof photoValue !== "string" && !(typeof photoValue === "object" && photoValue !== null && typeof photoValue.src === "string")) {
|
|
4211
|
+
throw new TypeError("Quote content must be a string or a text object (text a string or TextRun[]) with optional string attribution/role/source and an asset photo.");
|
|
3280
4212
|
}
|
|
4213
|
+
const richBody = Array.isArray(quote.text) ? quote.text : void 0;
|
|
4214
|
+
const quoteText = richBody ? annotationText(richBody) : quote.text;
|
|
3281
4215
|
const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale);
|
|
3282
4216
|
if (![box.x, box.y, box.width, box.height, scale, minimum].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || scale <= 0 || minimum <= 0) {
|
|
3283
4217
|
throw new RangeError("Quote dimensions, scale and minimum font size must be finite and positive.");
|
|
@@ -3287,78 +4221,96 @@ function layoutQuote(value, box, options = {}) {
|
|
|
3287
4221
|
const diagnostics = [], parts = [];
|
|
3288
4222
|
const report = (reason, diagnosticPath, roles, message) => diagnostics.push({ code: "text-overflow", reason, path: diagnosticPath, parts: roles, message });
|
|
3289
4223
|
const source = (sourcePath, text2, outputStart) => ({ path: sourcePath, start: 0, end: text2.length, outputStart, outputEnd: outputStart + text2.length });
|
|
3290
|
-
const add = (role, text2, sources, area, fontSize, fontFamily, fontWeight, partPath) => {
|
|
4224
|
+
const add = (role, text2, sources, area, fontSize, fontFamily, fontWeight, partPath, runs) => {
|
|
3291
4225
|
const requestedStyle = { fontFamily, fontWeight, italic: false, path: partPath };
|
|
3292
4226
|
const style = resolveTextStyle({ ...requestedStyle }, options.textMeasurement);
|
|
3293
4227
|
const requestedFontSize = gridFontSize(fontSize * scale, minimum);
|
|
3294
|
-
const part = { role, path: partPath, text: text2, sources, box: area, requestedFontSize, minFontSize: minimum, requestedStyle, style };
|
|
4228
|
+
const part = { role, path: partPath, text: text2, sources, box: area, requestedFontSize, minFontSize: minimum, requestedStyle, style, ...runs ? { runs } : {} };
|
|
3295
4229
|
parts.push(part);
|
|
3296
4230
|
return part;
|
|
3297
4231
|
};
|
|
3298
4232
|
let footer = "";
|
|
3299
4233
|
const footerSources = [];
|
|
3300
|
-
for (const field of ["attribution", "source"]) {
|
|
4234
|
+
for (const field of ["attribution", "role", "source"]) {
|
|
3301
4235
|
const text2 = quote[field];
|
|
3302
4236
|
if (!text2) continue;
|
|
3303
|
-
if (footer) footer += " - ";
|
|
4237
|
+
if (footer) footer += field === "role" ? "\n" : " - ";
|
|
3304
4238
|
footerSources.push(source(`${path}.${field}`, text2, footer.length));
|
|
3305
4239
|
footer += text2;
|
|
3306
4240
|
}
|
|
4241
|
+
const hasPhoto = photoValue !== void 0, hasFooter = footer !== "", hasBlock = hasPhoto || hasFooter;
|
|
4242
|
+
const photoPath = `${path}.photo`, rtl = options.direction === "rtl";
|
|
3307
4243
|
const bodyPath = shorthand ? path : `${path}.text`;
|
|
3308
4244
|
const body = add(
|
|
3309
4245
|
"body",
|
|
3310
|
-
`"${
|
|
3311
|
-
[source(bodyPath,
|
|
3312
|
-
{ x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - (
|
|
4246
|
+
`"${quoteText}"`,
|
|
4247
|
+
[source(bodyPath, quoteText, 1)],
|
|
4248
|
+
{ x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - (hasBlock ? 94 : 36) },
|
|
3313
4249
|
28,
|
|
3314
|
-
options.
|
|
4250
|
+
options.fontFamilies?.accent ?? options.fontFamilies?.heading ?? "sans-serif",
|
|
3315
4251
|
600,
|
|
3316
|
-
bodyPath
|
|
4252
|
+
bodyPath,
|
|
4253
|
+
richBody ? quoteBodyRuns(richBody) : void 0
|
|
3317
4254
|
);
|
|
3318
|
-
const attribution =
|
|
4255
|
+
const attribution = hasFooter ? add(
|
|
3319
4256
|
"footer",
|
|
3320
4257
|
footer,
|
|
3321
4258
|
footerSources,
|
|
3322
4259
|
{ x: box.x + 18, y: box.y + box.height - 58, width: box.width - 36, height: 40 },
|
|
3323
4260
|
17,
|
|
3324
|
-
options.
|
|
4261
|
+
options.fontFamilies?.body ?? "sans-serif",
|
|
3325
4262
|
500,
|
|
3326
4263
|
path
|
|
3327
4264
|
) : void 0;
|
|
4265
|
+
const footerRequested = attribution?.requestedFontSize ?? gridFontSize(17 * scale, minimum);
|
|
3328
4266
|
const usable = (area) => [area.x, area.y, area.width, area.height].every(Number.isFinite) && area.width > 0 && area.height > 0;
|
|
3329
|
-
const fit = (part, area, size = part.requestedFontSize, floor = minimum) => usable(area) ? fitText(part.text, area, size, floor, textWidthMeasurer(part.style, options.textMeasurement), options.direction)
|
|
4267
|
+
const fit = (part, area, size = part.requestedFontSize, floor = minimum) => !usable(area) ? void 0 : part.runs ? fitRichText(part.runs, area, size, floor, { style: part.style, textMeasurement: options.textMeasurement, ...options.citationMarker ? { citationMarker: options.citationMarker } : {}, ...options.direction ? { direction: options.direction } : {} }) : fitText(part.text, area, size, floor, textWidthMeasurer(part.style, options.textMeasurement), options.direction);
|
|
4268
|
+
const heightOf = (fit2) => "richLines" in fit2 ? fit2.height : fit2.lines.length * fit2.lineHeight;
|
|
3330
4269
|
const inner = { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - 36 };
|
|
3331
|
-
|
|
4270
|
+
let photo, photoFits = true;
|
|
4271
|
+
if (!hasBlock) body.fit = fit(body, body.box);
|
|
3332
4272
|
else if (usable(inner) && inner.height > 18) {
|
|
3333
4273
|
const available = inner.height - 18;
|
|
3334
4274
|
const preferredBody = fit(body, inner, body.requestedFontSize, body.requestedFontSize);
|
|
3335
4275
|
const minimumBody = body.requestedFontSize === minimum ? preferredBody : fit(body, inner, minimum, minimum);
|
|
3336
|
-
const preferredBodyHeight = preferredBody
|
|
3337
|
-
const minimumBodyHeight = minimumBody
|
|
4276
|
+
const preferredBodyHeight = heightOf(preferredBody);
|
|
4277
|
+
const minimumBodyHeight = heightOf(minimumBody);
|
|
3338
4278
|
let selected;
|
|
3339
|
-
for (const size of /* @__PURE__ */ new Set([
|
|
3340
|
-
const
|
|
3341
|
-
const
|
|
3342
|
-
const
|
|
3343
|
-
const
|
|
3344
|
-
const
|
|
4279
|
+
for (const size of /* @__PURE__ */ new Set([footerRequested, minimum])) {
|
|
4280
|
+
const diameter = hasPhoto ? PHOTO_RATIO * size : 0, gap = hasPhoto ? PHOTO_GAP * size : 0;
|
|
4281
|
+
const textArea = { ...inner, width: inner.width - diameter - gap, x: rtl ? inner.x : inner.x + diameter + gap };
|
|
4282
|
+
const natural = attribution ? fit(attribution, textArea, size, size) : void 0;
|
|
4283
|
+
const naturalHeight = natural ? natural.lines.length * natural.lineHeight : 0;
|
|
4284
|
+
const blockHeight = Math.max(naturalHeight, diameter);
|
|
4285
|
+
const lineHeight = natural?.lineHeight ?? size * 1.22;
|
|
4286
|
+
const preferredHeight = Math.max(40, blockHeight);
|
|
4287
|
+
const bodyReservation = Math.min(minimumBodyHeight, Math.max(minimumBody.lineHeight, available - lineHeight));
|
|
4288
|
+
const footerHeight = preferredBodyHeight + preferredHeight <= available + 0.01 ? preferredHeight : Math.min(blockHeight, Math.max(0, available - bodyReservation));
|
|
3345
4289
|
const bodyBox = { ...inner, height: available - footerHeight };
|
|
3346
4290
|
const footerBox = { ...inner, y: inner.y + inner.height - footerHeight, height: footerHeight };
|
|
3347
4291
|
const bodyFit = fit(body, bodyBox);
|
|
3348
|
-
const
|
|
3349
|
-
const
|
|
3350
|
-
const
|
|
4292
|
+
const photoBox = hasPhoto ? { x: rtl ? inner.x + inner.width - diameter : inner.x, y: footerBox.y + (footerHeight - diameter) / 2, width: diameter, height: diameter } : void 0;
|
|
4293
|
+
const textBox = attribution ? hasPhoto ? { ...textArea, y: footerBox.y + Math.max(0, footerHeight - naturalHeight) / 2, height: Math.min(naturalHeight, footerHeight) } : footerBox : void 0;
|
|
4294
|
+
const footerFit = attribution && natural && usable(footerBox) ? { ...natural, overflow: natural.overflow || naturalHeight > footerHeight + 0.01 } : void 0;
|
|
4295
|
+
const fitsPhoto = !hasPhoto || diameter <= footerHeight + 0.01 && (!attribution || usable(textArea));
|
|
4296
|
+
const overflow = !bodyFit || bodyFit.overflow || (attribution ? !footerFit || footerFit.overflow : false) || !fitsPhoto;
|
|
4297
|
+
const score = (body.requestedFontSize - (bodyFit?.fontSize ?? minimum) + footerRequested - size) / scale;
|
|
3351
4298
|
if (!selected || !overflow && (selected.overflow || score < selected.score) || overflow && selected.overflow) {
|
|
3352
|
-
selected = { bodyBox, footerBox, bodyFit, footerFit, score, overflow };
|
|
4299
|
+
selected = { bodyBox, footerBox, textBox, photoBox, bodyFit, footerFit, score, overflow, photoFits: fitsPhoto };
|
|
3353
4300
|
}
|
|
3354
4301
|
}
|
|
3355
4302
|
if (selected) {
|
|
3356
4303
|
body.box = selected.bodyBox;
|
|
3357
4304
|
body.fit = selected.bodyFit;
|
|
3358
|
-
attribution
|
|
3359
|
-
|
|
4305
|
+
if (attribution) {
|
|
4306
|
+
attribution.box = selected.textBox ?? selected.footerBox;
|
|
4307
|
+
attribution.fit = selected.footerFit;
|
|
4308
|
+
}
|
|
4309
|
+
if (selected.photoBox) photo = { path: photoPath, value: photoValue, box: selected.photoBox, shape: slideImageShape("circle", selected.photoBox) };
|
|
4310
|
+
photoFits = selected.photoFits;
|
|
3360
4311
|
}
|
|
3361
4312
|
}
|
|
4313
|
+
if (hasPhoto && !photo) photoFits = false;
|
|
3362
4314
|
for (const part of parts) {
|
|
3363
4315
|
const area = part.box;
|
|
3364
4316
|
if (!part.fit) {
|
|
@@ -3370,17 +4322,20 @@ function layoutQuote(value, box, options = {}) {
|
|
|
3370
4322
|
report("part-outside-cell", part.path, [part.role], `Quote ${part.role} extends outside its cell; increase the cell size or change the arrangement.`);
|
|
3371
4323
|
}
|
|
3372
4324
|
}
|
|
3373
|
-
if (
|
|
4325
|
+
if (hasPhoto && !photoFits) report("photo-fit", photoPath, ["footer"], "Quote photo does not fit beside the attribution at the readability floor; increase the cell size, shorten the text or remove the photo.");
|
|
4326
|
+
if (body?.fit && attribution?.fit && body.box.y + heightOf(body.fit) > attribution.box.y + 0.01 && attribution.box.y + attribution.fit.lines.length * attribution.fit.lineHeight > body.box.y + 0.01) {
|
|
3374
4327
|
report("part-overlap", path, ["body", "footer"], "Quote body and footer line boxes overlap; do not accept this layout without more space.");
|
|
4328
|
+
} else if (body?.fit && photo && body.box.y + heightOf(body.fit) > photo.box.y + 0.01) {
|
|
4329
|
+
report("part-overlap", path, ["body", "footer"], "Quote body and photo overlap; do not accept this layout without more space.");
|
|
3375
4330
|
}
|
|
3376
4331
|
if (diagnostics.length && options.overflow === "error") throw new OPFCompositionError(diagnostics);
|
|
3377
|
-
return { algorithm: "quote-flow-v1", textMeasurement: options.textMeasurement ? "provided" : "estimated", parts, diagnostics, overflow: diagnostics.length > 0 };
|
|
4332
|
+
return { algorithm: "quote-flow-v1", textMeasurement: options.textMeasurement ? "provided" : "estimated", parts, ...photo ? { photo } : {}, diagnostics, overflow: diagnostics.length > 0 };
|
|
3378
4333
|
}
|
|
3379
4334
|
function layoutMetric(value, box, options = {}) {
|
|
3380
4335
|
const scalar = typeof value === "string" || typeof value === "number";
|
|
3381
4336
|
const metric = scalar ? { value } : value;
|
|
3382
4337
|
const isValue = (input) => typeof input === "string" || typeof input === "number" && Number.isFinite(input);
|
|
3383
|
-
if (!metric || Array.isArray(metric) || !isValue(metric.value) || [metric.label, metric.description, metric.unit].some((field) => field !== void 0 && typeof field !== "string") || metric.delta !== void 0 && !isValue(metric.delta) || metric.trend !== void 0 && !["up", "down", "flat"].includes(metric.trend)) {
|
|
4338
|
+
if (!metric || Array.isArray(metric) || !isValue(metric.value) || [metric.label, metric.description, metric.unit].some((field) => field !== void 0 && typeof field !== "string") || metric.delta !== void 0 && !isValue(metric.delta) || metric.trend !== void 0 && !["up", "down", "flat"].includes(metric.trend) || metric.sentiment !== void 0 && !["positive", "negative", "neutral"].includes(metric.sentiment)) {
|
|
3384
4339
|
throw new TypeError("Metric content requires a finite numeric or string value and schema-valid display metadata.");
|
|
3385
4340
|
}
|
|
3386
4341
|
const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale);
|
|
@@ -3398,7 +4353,7 @@ function layoutMetric(value, box, options = {}) {
|
|
|
3398
4353
|
if (sourceValue === void 0) continue;
|
|
3399
4354
|
const text2 = String(sourceValue), path = scalar ? sourcePath : `${sourcePath}.${role}`;
|
|
3400
4355
|
const nominal = role === "value" ? Math.min(76 * scale, box.height * 0.28) : (role === "description" ? 20 : role === "trend" ? 18 : 23) * scale;
|
|
3401
|
-
const requestedStyle = { fontFamily: (role === "value" ? options.
|
|
4356
|
+
const requestedStyle = { fontFamily: (role === "value" ? options.fontFamilies?.heading : options.fontFamilies?.body) ?? "sans-serif", fontWeight: role === "value" ? 800 : role === "description" ? 400 : 500, italic: false, path };
|
|
3402
4357
|
const part = {
|
|
3403
4358
|
role,
|
|
3404
4359
|
path,
|
|
@@ -3544,24 +4499,28 @@ function layoutMetric(value, box, options = {}) {
|
|
|
3544
4499
|
}
|
|
3545
4500
|
}
|
|
3546
4501
|
if (diagnostics.length && options.overflow === "error") throw new OPFCompositionError(diagnostics);
|
|
3547
|
-
return { algorithm: "metric-flow-v1", alignment, textMeasurement: options.textMeasurement ? "provided" : "estimated", arrangement: selected.arrangement, attempts, parts, diagnostics, overflow: diagnostics.length > 0 };
|
|
4502
|
+
return { algorithm: "metric-flow-v1", alignment, textMeasurement: options.textMeasurement ? "provided" : "estimated", arrangement: selected.arrangement, ...metric.sentiment === void 0 ? {} : { sentiment: metric.sentiment }, attempts, parts, diagnostics, overflow: diagnostics.length > 0 };
|
|
3548
4503
|
}
|
|
4504
|
+
var TIMELINE_STATUS_VALUES = ["done", "current", "planned"];
|
|
4505
|
+
var TIMELINE_RING_RATIO = 1.6;
|
|
3549
4506
|
function layoutTimeline(value, box, options = {}) {
|
|
3550
4507
|
const shorthand = Array.isArray(value), timeline = shorthand ? { events: value } : value;
|
|
3551
4508
|
if (!timeline || !Array.isArray(timeline.events) || !timeline.events.length || [timeline.name, timeline.description].some((field) => field !== void 0 && typeof field !== "string") || timeline.events.some((event) => !event || typeof event.what !== "string" || [event.when, event.description].some((field) => field !== void 0 && typeof field !== "string"))) {
|
|
3552
4509
|
throw new TypeError("Timeline content requires ordered events with string labels and optional string metadata.");
|
|
3553
4510
|
}
|
|
4511
|
+
if (timeline.events.some((event) => event.status !== void 0 && !TIMELINE_STATUS_VALUES.includes(event.status))) throw new TypeError("Timeline event status must be 'done', 'current' or 'planned'.");
|
|
3554
4512
|
const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale), padding = (options.textRasterPadding ?? 1) * scale;
|
|
3555
4513
|
if (![box.x, box.y, box.width, box.height, scale, minimum, padding].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || scale <= 0 || minimum <= 0 || padding < 0) throw new RangeError("Timeline dimensions, scale and minimum must be positive, with finite nonnegative raster padding.");
|
|
3556
4514
|
if (options.overflow !== void 0 && !["warn", "error"].includes(options.overflow)) throw new RangeError("Invalid timeline overflow policy.");
|
|
3557
4515
|
const outlines = options.textMeasurement?.outlineBounds !== void 0, rtl = options.direction === "rtl";
|
|
3558
4516
|
if (outlines && typeof options.textMeasurement?.outlineBounds !== "function") throw new TypeError("Text outline provider must be a function.");
|
|
3559
4517
|
const path = options.path ?? "timeline", eventPath = (index) => shorthand ? `${path}.${index}` : `${path}.events.${index}`;
|
|
3560
|
-
const fonts = resolveFontFamilies(options.
|
|
4518
|
+
const fonts = resolveFontFamilies(options.fontFamilies), source = [];
|
|
3561
4519
|
const add = (role, text2, partPath, size, weight, eventIndex) => {
|
|
3562
4520
|
if (text2 === void 0) return;
|
|
3563
|
-
const
|
|
3564
|
-
|
|
4521
|
+
const status = eventIndex === void 0 ? void 0 : timeline.events[eventIndex].status;
|
|
4522
|
+
const requestedStyle = { fontFamily: fonts.body, fontWeight: status === "current" && role === "what" ? 700 : weight, italic: false, path: partPath };
|
|
4523
|
+
source.push({ role, eventIndex, ...status ? { status } : {}, path: partPath, text: text2, sources: [{ path: partPath, start: 0, end: text2.length }], box: { ...box }, alignment: "center", requestedFontSize: gridFontSize(size * scale, minimum), minFontSize: minimum, requestedStyle, style: resolveTextStyle({ ...requestedStyle }, options.textMeasurement) });
|
|
3565
4524
|
};
|
|
3566
4525
|
add("name", timeline.name, `${path}.name`, 24, 700);
|
|
3567
4526
|
add("description", timeline.description, `${path}.description`, 18, 400);
|
|
@@ -3631,12 +4590,18 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
3631
4590
|
y += placed.box.height + 8 * scale;
|
|
3632
4591
|
}
|
|
3633
4592
|
const available = box.y + box.height - y, count = events.length, radius = Math.min(9 * scale, box.width / Math.max(2, count) / 5, Math.max(scale, available) * 0.04);
|
|
4593
|
+
const statusOf = (index) => timeline.events[index].status, ringRadius = radius * TIMELINE_RING_RATIO, strokeWidth = Math.min(2 * scale, radius / 2);
|
|
4594
|
+
const hasRing = timeline.events.some((event) => event.status === "current");
|
|
4595
|
+
const marker = (index, x, y2) => {
|
|
4596
|
+
const status = statusOf(index);
|
|
4597
|
+
return { path: eventPath(index), eventIndex: index, x, y: y2, radius, ...status ? { status } : {}, ...status === "current" ? { ring: { radius: ringRadius } } : {}, ...status === "current" || status === "planned" ? { strokeWidth } : {} };
|
|
4598
|
+
};
|
|
3634
4599
|
if (arrangement === "alternating") {
|
|
3635
4600
|
const width = box.width / Math.max(2, count), step = (box.width - width) / Math.max(1, count - 1), start = count === 1 ? box.x + box.width / 2 : box.x + width / 2;
|
|
3636
4601
|
const lineY = y + Math.max(scale, available) * 0.46;
|
|
3637
4602
|
events.forEach((fields2, index) => {
|
|
3638
4603
|
const x = start + (rtl ? count - 1 - index : index) * step, top = index % 2 === 0 ? y : lineY + 24 * scale, bottom = index % 2 === 0 ? lineY - 24 * scale : box.y + box.height;
|
|
3639
|
-
markers.push(
|
|
4604
|
+
markers.push(marker(index, x, lineY));
|
|
3640
4605
|
let cursor = top;
|
|
3641
4606
|
for (const part of fields2) {
|
|
3642
4607
|
const placed = place(part, x - width / 2, cursor, width, "center");
|
|
@@ -3645,7 +4610,8 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
3645
4610
|
}
|
|
3646
4611
|
});
|
|
3647
4612
|
} else {
|
|
3648
|
-
const
|
|
4613
|
+
const lead = hasRing ? ringRadius + strokeWidth / 2 : radius, gap = 24 * scale + (lead - radius);
|
|
4614
|
+
const x = rtl ? box.x + box.width - lead : box.x + lead, textX = rtl ? box.x : box.x + gap, width = box.width - gap;
|
|
3649
4615
|
events.forEach((fields2, index) => {
|
|
3650
4616
|
const top = y;
|
|
3651
4617
|
let first2;
|
|
@@ -3654,13 +4620,16 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
3654
4620
|
first2 ??= placed;
|
|
3655
4621
|
y += placed.box.height;
|
|
3656
4622
|
}
|
|
3657
|
-
markers.push(
|
|
4623
|
+
markers.push(marker(index, x, top + Math.min(first2?.box.height ?? 2 * radius, 2 * radius) / 2));
|
|
3658
4624
|
y += 16 * scale;
|
|
3659
4625
|
});
|
|
3660
4626
|
}
|
|
3661
|
-
for (const
|
|
3662
|
-
|
|
3663
|
-
|
|
4627
|
+
for (const marker2 of markers) {
|
|
4628
|
+
const extent = (marker2.ring?.radius ?? marker2.radius) + (marker2.strokeWidth ?? 0) / 2;
|
|
4629
|
+
if (marker2.x - extent < box.x - 0.01 || marker2.y - extent < box.y - 0.01 || marker2.x + extent > box.x + box.width + 0.01 || marker2.y + extent > box.y + box.height + 0.01) {
|
|
4630
|
+
diagnostics.push({ code: "text-overflow", reason: "event-space", path: marker2.path, message: "Timeline marker has no usable space; increase the cell or paginate events." });
|
|
4631
|
+
score2 += 1;
|
|
4632
|
+
}
|
|
3664
4633
|
}
|
|
3665
4634
|
const first = markers[0], last = markers.at(-1), connector = rtl ? { x1: Math.min(first.x, last.x), y1: first.y, x2: Math.max(first.x, last.x), y2: last.y } : { x1: first.x, y1: first.y, x2: last.x, y2: last.y };
|
|
3666
4635
|
const candidate = { arrangement, parts, markers, connector, diagnostics, score: score2 };
|
|
@@ -3771,7 +4740,7 @@ function layoutCode(value, box, options = {}) {
|
|
|
3771
4740
|
const path = options.path ?? "code", inner = { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - 36 };
|
|
3772
4741
|
const parts = [], diagnostics = [];
|
|
3773
4742
|
const add = (role, text2, partPath, generated = false) => {
|
|
3774
|
-
const requestedStyle = { fontFamily: options.
|
|
4743
|
+
const requestedStyle = { fontFamily: options.fontFamilies?.code ?? "monospace", fontWeight: role === "body" ? 400 : 700, italic: false, path: partPath };
|
|
3775
4744
|
const part = {
|
|
3776
4745
|
role,
|
|
3777
4746
|
path: partPath,
|
|
@@ -3857,7 +4826,8 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
|
3857
4826
|
if (typeof run?.text !== "string" || run.fontSize !== void 0 && (!Number.isFinite(run.fontSize) || run.fontSize <= 0)) throw new RangeError("Rich text runs need text and a positive finite font size.");
|
|
3858
4827
|
const start = offset;
|
|
3859
4828
|
offset += run.text.length;
|
|
3860
|
-
const
|
|
4829
|
+
const resolvedStyle = resolveTextStyle({ ...options.style, fontFamily: run.fontFamily ?? (run.code === true ? options.codeFontFamily ?? "monospace" : options.style.fontFamily), fontWeight: run.bold === void 0 ? options.style.fontWeight : run.bold ? 700 : 400, italic: run.italic ?? options.style.italic, path: options.style.path ? `${options.style.path}.${runIndex}` : void 0 }, options.textMeasurement);
|
|
4830
|
+
const style = typeof run.lang === "string" && run.lang ? { ...resolvedStyle, lang: run.lang } : resolvedStyle;
|
|
3861
4831
|
const marker = options.citationMarker && options.style.path && run.text ? options.citationMarker(`${options.style.path}.${runIndex}`) : void 0;
|
|
3862
4832
|
return { run, runIndex, start, end: offset, style, ...marker ? { marker } : {} };
|
|
3863
4833
|
});
|
|
@@ -3974,15 +4944,15 @@ var PICTURE_BULLET_SCALE = 0.65;
|
|
|
3974
4944
|
function fitList(input, box, requestedSize = 25, minFontSize = 16, options = { style: { fontFamily: "sans-serif", fontWeight: 400 } }) {
|
|
3975
4945
|
if (!Array.isArray(input) || ![box.width, box.height, requestedSize, minFontSize].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("List content, dimensions and font sizes must be valid.");
|
|
3976
4946
|
const source = input.map((value, index) => {
|
|
3977
|
-
const
|
|
3978
|
-
const text2 =
|
|
4947
|
+
const object2 = typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
4948
|
+
const text2 = object2 ? object2.text : value, description = object2?.description, level = object2?.level ?? 0;
|
|
3979
4949
|
if (!Number.isInteger(level) || level < 0) throw new RangeError("List levels must be nonnegative integers.");
|
|
3980
4950
|
const runs = (value2) => typeof value2 === "string" ? [value2] : value2;
|
|
3981
4951
|
if (!Array.isArray(runs(text2)) || description !== void 0 && !Array.isArray(runs(description))) throw new TypeError("List text and descriptions must be strings or text runs.");
|
|
3982
4952
|
const base = options.style.path ? `${options.style.path}.${index}` : void 0;
|
|
3983
4953
|
const plain = (value2) => typeof value2 === "string" ? value2 : value2.map((run) => typeof run === "string" ? run : run.text).join("");
|
|
3984
4954
|
const direction = options.direction === "rtl" ? paragraphDirection(plain(text2), "rtl") : void 0;
|
|
3985
|
-
return { index, level, direction, value: text2, descriptionValue: description, textPath: base ? base + (
|
|
4955
|
+
return { index, level, direction, value: text2, descriptionValue: description, textPath: base ? base + (object2 ? ".text" : "") : void 0, descriptionPath: base ? base + ".description" : void 0, runs: runs(text2), descriptionRuns: description === void 0 ? void 0 : runs(description) };
|
|
3986
4956
|
});
|
|
3987
4957
|
const numbers = options.numbering === void 0 ? void 0 : listNumbers(input, options.numbering);
|
|
3988
4958
|
const markerStyleFor = (item) => {
|
|
@@ -4079,13 +5049,13 @@ function layoutTable(value, box, options = {}) {
|
|
|
4079
5049
|
const cellMinimum = (cell) => Array.isArray(cell.value) ? richMinimum(cell.value, requested, minimum) : minimum;
|
|
4080
5050
|
const fitCell = (cell, height, min) => {
|
|
4081
5051
|
const textBox = { width: Math.max(scale, cell.width), height: Math.max(scale, height) };
|
|
4082
|
-
return Array.isArray(cell.value) ? fitRichText(cell.value, textBox, requested, min, { style: cell.textStyle, textMeasurement: options.textMeasurement, uniformLineHeight: true, direction: options.direction }) : fitText(flatten(cell.value), textBox, requested, min, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement), options.direction);
|
|
5052
|
+
return Array.isArray(cell.value) ? fitRichText(cell.value, textBox, requested, min, { style: cell.textStyle, ...options.codeFontFamily ? { codeFontFamily: options.codeFontFamily } : {}, textMeasurement: options.textMeasurement, uniformLineHeight: true, direction: options.direction }) : fitText(flatten(cell.value), textBox, requested, min, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement), options.direction);
|
|
4083
5053
|
};
|
|
4084
5054
|
const textHeight = (fit) => "height" in fit ? fit.height : fit.lines.length * fit.lineHeight;
|
|
4085
5055
|
const required = (cell, natural2) => {
|
|
4086
5056
|
const floor = cellMinimum(cell), size = gridFontSize(natural2 ? Math.max(requested, floor) : floor, floor);
|
|
4087
5057
|
const textBox = { width: Math.max(scale, cell.width), height: scale };
|
|
4088
|
-
const fit = Array.isArray(cell.value) ? richTextLayouter(cell.value, textBox, requested, { style: cell.textStyle, textMeasurement: options.textMeasurement, uniformLineHeight: true }, minimum)(size) : fitText(flatten(cell.value), textBox, size, size, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement));
|
|
5058
|
+
const fit = Array.isArray(cell.value) ? richTextLayouter(cell.value, textBox, requested, { style: cell.textStyle, ...options.codeFontFamily ? { codeFontFamily: options.codeFontFamily } : {}, textMeasurement: options.textMeasurement, uniformLineHeight: true }, minimum)(size) : fitText(flatten(cell.value), textBox, size, size, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement));
|
|
4089
5059
|
return textHeight(fit) + (cell.padding.top + cell.padding.bottom) * scale;
|
|
4090
5060
|
};
|
|
4091
5061
|
const natural = Array(grid.rowCount).fill(0), needed = Array(grid.rowCount).fill(0);
|
|
@@ -4106,7 +5076,7 @@ function layoutTable(value, box, options = {}) {
|
|
|
4106
5076
|
const ys = [box.y];
|
|
4107
5077
|
for (const height of heights) ys.push(ys.at(-1) + height);
|
|
4108
5078
|
let overflow = false;
|
|
4109
|
-
const
|
|
5079
|
+
const rows3 = heights.map((height, r) => ({ box: { x: box.x, y: ys[r], width: box.width, height }, cells: [] }));
|
|
4110
5080
|
for (const cell of cells) {
|
|
4111
5081
|
const cellBox = { x: box.x + (options.direction === "rtl" ? columnCount - cell.column - cell.colSpan : cell.column) * cellWidth, y: ys[cell.row], width: cell.colSpan * cellWidth, height: ys[cell.row + cell.rowSpan] - ys[cell.row] };
|
|
4112
5082
|
const available = cellBox.height - (cell.padding.top + cell.padding.bottom) * scale;
|
|
@@ -4114,12 +5084,12 @@ function layoutTable(value, box, options = {}) {
|
|
|
4114
5084
|
const offset = cell.style.verticalAlign === "bottom" ? Math.max(0, available - height) : cell.style.verticalAlign === "middle" ? Math.max(0, (available - height) / 2) : 0;
|
|
4115
5085
|
const textBox = { x: cellBox.x + cell.padding.left * scale, y: cellBox.y + cell.padding.top * scale + offset, width: Math.max(scale, cell.width), height: Math.max(scale, available - offset) };
|
|
4116
5086
|
overflow ||= cell.width <= 0 || available <= 0 || fit.overflow;
|
|
4117
|
-
|
|
5087
|
+
rows3[cell.row].cells.push({ value: cell.value, input: cell.input, path: cell.valuePath, sourcePath: cell.path, style: cell.style, row: cell.row, column: cell.column, rowSpan: cell.rowSpan, colSpan: cell.colSpan, header: cell.header, rich: Array.isArray(cell.value), box: cellBox, textBox, textStyle: resolveTextStyle(cell.textStyle, options.textMeasurement), fit, ...fit.directions ? { direction: fit.directions[0] } : {} });
|
|
4118
5088
|
}
|
|
4119
|
-
return { rows:
|
|
5089
|
+
return { rows: rows3, columnCount, height: sum(heights), overflow };
|
|
4120
5090
|
}
|
|
4121
5091
|
function tableOverflows(value, box, scale, settings, options, path) {
|
|
4122
|
-
return box.width <= 0 || box.height <= 0 || layoutTable(value, box, { scale, minFontSize: settings.minFontSize, fontFamily: options.
|
|
5092
|
+
return box.width <= 0 || box.height <= 0 || layoutTable(value, box, { scale, minFontSize: settings.minFontSize, fontFamily: options.fontFamilies?.body, ...options.fontFamilies?.code ? { codeFontFamily: options.fontFamilies.code } : {}, textMeasurement: options.textMeasurement, path, presentation: options.presentation }).overflow;
|
|
4123
5093
|
}
|
|
4124
5094
|
function flatten(value) {
|
|
4125
5095
|
if (value == null) return "";
|
|
@@ -4135,10 +5105,10 @@ function regionParts(key) {
|
|
|
4135
5105
|
};
|
|
4136
5106
|
const parts = key.split(":");
|
|
4137
5107
|
if (parts.length === 2) {
|
|
4138
|
-
const r = span(parts[0],
|
|
5108
|
+
const r = span(parts[0], rows2), c = span(parts[1], columns);
|
|
4139
5109
|
if (r && c) return [r, c];
|
|
4140
5110
|
} else if (parts.length === 1) {
|
|
4141
|
-
const r = span(key,
|
|
5111
|
+
const r = span(key, rows2), c = span(key, columns);
|
|
4142
5112
|
if (r) return [r, [0, 1, 2]];
|
|
4143
5113
|
if (c) return [[0, 1, 2], c];
|
|
4144
5114
|
}
|
|
@@ -4187,7 +5157,8 @@ function composeSlide(input, options = {}) {
|
|
|
4187
5157
|
const scale = Math.min(width, height) / 720;
|
|
4188
5158
|
const deckDirection = options.direction ?? resolveSlideDirection(options.presentation, options.slideIndex);
|
|
4189
5159
|
const rtl = deckDirection === "rtl", textDirection = rtl ? "rtl" : void 0;
|
|
4190
|
-
const
|
|
5160
|
+
const hints = resolveDesignHints({ slide, layout, presentation: options.presentation, slideIndex: options.slideIndex, deck: { titleAlignment: options.titleAlignment, contentAlignment: options.contentAlignment, contentBox: options.contentBox } });
|
|
5161
|
+
const hasCards = hints.contentBox ?? false;
|
|
4191
5162
|
const composition = { ...record5(layout.composition), ...record5(slide.composition) };
|
|
4192
5163
|
assertComposition(composition);
|
|
4193
5164
|
const padding = (composition.padding ?? 0.08) * Math.min(width, height);
|
|
@@ -4196,15 +5167,13 @@ function composeSlide(input, options = {}) {
|
|
|
4196
5167
|
const rasterPadding = (options.textRasterPadding ?? 1) * scale;
|
|
4197
5168
|
if (!Number.isFinite(rasterPadding) || rasterPadding < 0) throw new RangeError("Text raster padding must be finite and nonnegative.");
|
|
4198
5169
|
let coverGroup = false;
|
|
4199
|
-
const alignmentFor = (field) => (field === "title" || coverGroup && (field === "tag" || field === "subtitle") &&
|
|
5170
|
+
const alignmentFor = (field) => (field === "title" || coverGroup && (field === "tag" || field === "subtitle") && hints.sources.contentAlignment !== "slide" ? hints.titleAlignment : hints.contentAlignment) ?? "left";
|
|
4200
5171
|
const styleFor = (field, path2) => resolveTextStyle({
|
|
4201
|
-
fontFamily: (field === "title" ? options.
|
|
5172
|
+
fontFamily: (field === "title" ? options.fontFamilies?.heading : field === "code" ? options.fontFamilies?.code : field === "tag" ? options.fontFamilies?.accent ?? options.fontFamilies?.body : options.fontFamilies?.body) ?? (field === "code" ? "monospace" : "sans-serif"),
|
|
4202
5173
|
fontWeight: field === "title" ? 700 : 400,
|
|
4203
5174
|
path: path2
|
|
4204
5175
|
}, options.textMeasurement);
|
|
4205
|
-
const
|
|
4206
|
-
const designHint = (field) => slideDesign[field] !== void 0 ? { value: slideDesign[field], path: `slides.${options.slideIndex ?? 0}.design.${field}` } : deckDesign[field] !== void 0 ? { value: deckDesign[field], path: `design.${field}` } : void 0;
|
|
4207
|
-
const listBullet = designHint("listBullet");
|
|
5176
|
+
const listBullet = hints.listBullet !== void 0 ? { value: hints.listBullet, path: hints.paths.listBullet } : void 0;
|
|
4208
5177
|
const bulletImage = listBullet?.value === "image" ? (() => {
|
|
4209
5178
|
const resolved = resolveLogo(options.presentation, slide, { slot: "icon", onDark: options.darkBackground, slideIndex: options.slideIndex });
|
|
4210
5179
|
return resolved ? { source: resolved.source, path: resolved.path } : void 0;
|
|
@@ -4212,9 +5181,9 @@ function composeSlide(input, options = {}) {
|
|
|
4212
5181
|
const widthFor = (field, path2) => textWidthMeasurer(styleFor(field, path2), options.textMeasurement);
|
|
4213
5182
|
const citations = slideCitations(slide, options.slideIndex ?? 0, options.presentation);
|
|
4214
5183
|
const citationMarker = citations ? (runPath) => citations.markers.get(runPath) : void 0;
|
|
4215
|
-
const richOptions = (style) => ({ style, textMeasurement: options.textMeasurement, ...citationMarker ? { citationMarker } : {}, ...rtl ? { direction: "rtl" } : {} });
|
|
5184
|
+
const richOptions = (style) => ({ style, textMeasurement: options.textMeasurement, ...options.fontFamilies?.code ? { codeFontFamily: options.fontFamilies.code } : {}, ...citationMarker ? { citationMarker } : {}, ...rtl ? { direction: "rtl" } : {} });
|
|
4216
5185
|
const fitPlacedText = (field, value, text2, box, size, minimum, path2, explicitAlignment) => {
|
|
4217
|
-
const style = styleFor(field, path2), rich = field === "text" && Array.isArray(value);
|
|
5186
|
+
const style = styleFor(field, path2), rich = (field === "text" || headings.has(field)) && Array.isArray(value);
|
|
4218
5187
|
if (!options.textMeasurement?.outlineBounds) return rich ? fitRichText(value, box, size, minimum, richOptions(style)) : fitText(text2, box, size, minimum, textWidthMeasurer(style, options.textMeasurement), textDirection);
|
|
4219
5188
|
const alignment = explicitAlignment ?? alignmentFor(field);
|
|
4220
5189
|
const richLayout = rich ? richTextLayouter(value, box, size, richOptions(style), minimum) : void 0;
|
|
@@ -4307,12 +5276,12 @@ function composeSlide(input, options = {}) {
|
|
|
4307
5276
|
let y = logo ? logo.box.y + logo.box.height + gap : headingTop;
|
|
4308
5277
|
const headingItems = [];
|
|
4309
5278
|
for (const field of ["tag", "title", "subtitle"]) {
|
|
4310
|
-
if (!slide[field]) continue;
|
|
5279
|
+
if (!slide[field] || Array.isArray(slide[field]) && !annotationText(slide[field])) continue;
|
|
4311
5280
|
const requested = (field === "title" ? 54 : field === "tag" ? 16 : 25) * scale;
|
|
4312
5281
|
const maxHeight = Math.max(height * (field === "title" ? 0.26 : field === "subtitle" ? 0.12 : 0.045), minSize * 1.22 + 2 * rasterPadding);
|
|
4313
5282
|
const box = { x: area.left + padding, y, width: area.right - area.left - padding * 2, height: maxHeight };
|
|
4314
|
-
const text2 = fitPlacedText(field, slide[field],
|
|
4315
|
-
box.height = Math.min(maxHeight, Math.max(text2.lines.length * text2.lineHeight, text2.placement?.height ?? 0));
|
|
5283
|
+
const text2 = fitPlacedText(field, slide[field], annotationText(slide[field]), box, requested, minSize, `${path}.${field}`);
|
|
5284
|
+
box.height = Math.min(maxHeight, Math.max("richLines" in text2 ? text2.height : text2.lines.length * text2.lineHeight, text2.placement?.height ?? 0));
|
|
4316
5285
|
if (furniture && box.y + box.height > bodyBottom + 0.01) diagnostics.push({ code: "text-overflow", path: `${path}.${field}`, message: "Repeated furniture leaves too little room for this heading. Change the header/footer or slide design." });
|
|
4317
5286
|
const item = { path: `${path}.${field}`, field, type: "text", value: slide[field], payload: { text: slide[field] }, box, text: text2, textStyle: styleFor(field, `${path}.${field}`), composition, alignment: alignmentFor(field) };
|
|
4318
5287
|
headingItems.push(item);
|
|
@@ -4377,22 +5346,23 @@ function composeSlide(input, options = {}) {
|
|
|
4377
5346
|
return acceptedBox({ x: frame.x + padding2, y: frame.y + padding2, width: frame.width - 2 * padding2, height: frame.height - 2 * padding2 });
|
|
4378
5347
|
};
|
|
4379
5348
|
const measureQuote = (node, box, settings) => layoutQuote(node.value, acceptedBox(box), {
|
|
4380
|
-
|
|
5349
|
+
fontFamilies: options.fontFamilies,
|
|
4381
5350
|
textMeasurement: options.textMeasurement,
|
|
4382
5351
|
scale,
|
|
4383
5352
|
minFontSize: settings.minFontSize,
|
|
4384
5353
|
path: node.path,
|
|
4385
|
-
direction: textDirection
|
|
5354
|
+
direction: textDirection,
|
|
5355
|
+
...citationMarker ? { citationMarker } : {}
|
|
4386
5356
|
});
|
|
4387
5357
|
const measureCode = (node, box, settings) => layoutCode(node.value, acceptedBox(box), {
|
|
4388
|
-
|
|
5358
|
+
fontFamilies: options.fontFamilies,
|
|
4389
5359
|
textMeasurement: options.textMeasurement,
|
|
4390
5360
|
scale,
|
|
4391
5361
|
minFontSize: settings.minFontSize,
|
|
4392
5362
|
path: node.path
|
|
4393
5363
|
});
|
|
4394
5364
|
const measureMetric = (node, box, settings) => layoutMetric(node.value, acceptedBox(box), {
|
|
4395
|
-
|
|
5365
|
+
fontFamilies: options.fontFamilies,
|
|
4396
5366
|
textMeasurement: options.textMeasurement,
|
|
4397
5367
|
scale,
|
|
4398
5368
|
minFontSize: settings.minFontSize,
|
|
@@ -4402,7 +5372,7 @@ function composeSlide(input, options = {}) {
|
|
|
4402
5372
|
direction: textDirection
|
|
4403
5373
|
});
|
|
4404
5374
|
const measureTimeline = (node, box, settings) => layoutTimeline(node.value, acceptedBox(box), {
|
|
4405
|
-
|
|
5375
|
+
fontFamilies: options.fontFamilies,
|
|
4406
5376
|
textMeasurement: options.textMeasurement,
|
|
4407
5377
|
scale,
|
|
4408
5378
|
minFontSize: settings.minFontSize,
|
|
@@ -4539,18 +5509,17 @@ function composeSlide(input, options = {}) {
|
|
|
4539
5509
|
};
|
|
4540
5510
|
const placeholders = Array.isArray(layout.placeholders) ? layout.placeholders.filter((p) => !headings.has(p.type)) : [];
|
|
4541
5511
|
if (slideImage?.replacesContent) {
|
|
4542
|
-
const picture = placeholders.findIndex((p) => p.type === "
|
|
5512
|
+
const picture = placeholders.findIndex((p) => p.type === "image");
|
|
4543
5513
|
if (picture >= 0) placeholders.splice(picture, 1);
|
|
4544
5514
|
}
|
|
4545
5515
|
const ownMode = record5(slide.composition).mode;
|
|
4546
|
-
const direction =
|
|
4547
|
-
const directionMode = direction === "vertical" ? "column" : direction === "horizontal" ? "row" :
|
|
4548
|
-
const
|
|
4549
|
-
const chartHint = designHint("chartPrimary")?.value ?? (typeof layout.contentTypeChartPrimary === "string" ? layout.contentTypeChartPrimary.toLowerCase() : void 0);
|
|
5516
|
+
const direction = hints.contentDirection;
|
|
5517
|
+
const directionMode = direction === "vertical" ? "column" : direction === "horizontal" ? "row" : "auto";
|
|
5518
|
+
const chartHint = hints.chartPrimary;
|
|
4550
5519
|
const chartSide = chartHint === "left" || chartHint === "right" || chartHint === "top" || chartHint === "bottom" ? chartHint : void 0;
|
|
4551
5520
|
const chartIndex = pending.findIndex((node) => !node.children && node.field === "chart");
|
|
4552
5521
|
const chartPrimary = chartSide !== void 0 && !ownMode && !regions.length && chartIndex >= 0 && pending.some((node) => node.children || node.field !== "chart") ? chartSide : void 0;
|
|
4553
|
-
const rootSettings = chartPrimary ? { ...composition, mode: chartPrimary === "left" || chartPrimary === "right" ? "row" : "column", columns: void 0, weights: chartPrimary === "left" || chartPrimary === "top" ? [3, 2] : [2, 3] } : { ...composition, mode: composition.mode ?? directionMode
|
|
5522
|
+
const rootSettings = chartPrimary ? { ...composition, mode: chartPrimary === "left" || chartPrimary === "right" ? "row" : "column", columns: void 0, weights: chartPrimary === "left" || chartPrimary === "top" ? [3, 2] : [2, 3] } : { ...composition, mode: composition.mode ?? directionMode };
|
|
4554
5523
|
if (chartPrimary) {
|
|
4555
5524
|
const primary = pending[chartIndex], rest = pending.filter((_, index) => index !== chartIndex);
|
|
4556
5525
|
const container = { field: "blocks", type: "group", value: rest.map((node) => node.payload), path, payload: {}, children: rest, composition: {}, synthetic: true };
|
|
@@ -4595,7 +5564,7 @@ function composeSlide(input, options = {}) {
|
|
|
4595
5564
|
} : void 0;
|
|
4596
5565
|
if (failures.length) throw new OPFCompositionError(failures, explanation);
|
|
4597
5566
|
diagnostics.push(...slideImageDiagnostics, ...numberingDiagnostics);
|
|
4598
|
-
return { width, height, contentBox, items, groups, flows, diagnostics, composition, ...furniture ? { furniture } : {}, ...slideImage ? { slideImage } : {}, ...logo ? { logo } : {}, ...rtl ? { direction: "rtl" } : {}, ...footnotes ? { footnotes } : {}, ...explanation ? { explanation } : {} };
|
|
5567
|
+
return { width, height, contentBox, items, groups, flows, diagnostics, composition, design: hints, ...furniture ? { furniture } : {}, ...slideImage ? { slideImage } : {}, ...logo ? { logo } : {}, ...rtl ? { direction: "rtl" } : {}, ...footnotes ? { footnotes } : {}, ...explanation ? { explanation } : {} };
|
|
4599
5568
|
}
|
|
4600
5569
|
function resolveCanvasDimensions(input) {
|
|
4601
5570
|
const presets = {
|
|
@@ -4604,6 +5573,9 @@ function resolveCanvasDimensions(input) {
|
|
|
4604
5573
|
standard: [10, 7.5],
|
|
4605
5574
|
"4:3": [10, 7.5],
|
|
4606
5575
|
"16:10": [10, 6.25],
|
|
5576
|
+
"1:1": [7.5, 7.5],
|
|
5577
|
+
"4:5": [7.5, 9.375],
|
|
5578
|
+
"9:16": [7.5, 40 / 3],
|
|
4607
5579
|
letter: [11, 8.5],
|
|
4608
5580
|
a4: [11.69, 8.27]
|
|
4609
5581
|
};
|
|
@@ -4615,4 +5587,4 @@ function resolveCanvasDimensions(input) {
|
|
|
4615
5587
|
return { width, height };
|
|
4616
5588
|
}
|
|
4617
5589
|
|
|
4618
|
-
export { CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FONT_SCHEME, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_SLIDE_NUMBER_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_ROMAN_VALUE, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCompositionError, OPFVariableError, PICTURE_BULLET_SCALE, VARIABLE_KINDS, annotationText, bareIdPattern, captionSettings,
|
|
5590
|
+
export { CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CHART_HIGHLIGHT_MUTED_MIN_CONTRAST, CHART_HIGHLIGHT_MUTED_MIX, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, CODE_HIGHLIGHT_LANGUAGES, CODE_HIGHLIGHT_MAX_LENGTH, CODE_PANEL_BACKGROUND, CODE_PANEL_FOREGROUND, CODE_SYNTAX_MIN_CONTRAST, DARK_BACKGROUND_LUMINANCE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FONT_SCHEME, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_SLIDE_NUMBER_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, DESIGN_HINT_KEYS, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, LAYOUT_BODY_KINDS, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_ROMAN_VALUE, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCompositionError, OPFVariableError, PATTERN_PRESETS, PATTERN_PRESET_ALIASES, PATTERN_TILE_SIZE, PICTURE_BULLET_SCALE, SURFACE_ALT_MIN_CONTRAST, SURFACE_ALT_MIX, TIMELINE_OUTLINE_MIN_CONTRAST, TIMELINE_STATUSES, TIMELINE_TEXT_MIN_CONTRAST, VARIABLE_KINDS, annotationText, bareIdPattern, captionSettings, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, citationMarkerText, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, composeSlide, datasetDiagnostics, defaultSlideBackground, fitList, fitRichText, fitText, formatChartLabelNumber, formatChartLabelPercent, formatDataNumber, formatFurnitureDate, formatListNumber, formatSlideNumber, formatVariableNumber, fromExcelNumberFormat, hasContentVariables, inlineChartData, inlineDatasets, inlineTableData, instantiateForValidation, intrinsicImageSize, isDarkColor, isDatasetRef, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutTable, layoutTimeline, layoutWatermark, listBuiltinVariables, listNumbers, listVariables, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, promotedRegionKeys, readingRows, referencesSlide, resolveCanvasDimensions, resolveChartData, resolveChartOptions, resolveCodeLanguage, resolveColorRef, resolveColorRoles, resolveDesignHints, resolveFontFamilies, resolveFontSchemeReference, resolveLogo, resolveNumbering, resolvePatternPreset, resolveScriptFonts, resolveSlideDirection, resolveSocialProfile, resolveTableData, resolveTextStyle, resolveVariables, scriptFontRole, sliceNumberedItems, slideCitations, slideImageShape, snapFontSizeDown, snapFontSizeUp, suggestChartNumberFix, surfaceAltColor, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, timelineMarkerShapes, timelineTextColor, toExcelNumberFormat, tokenizeCode, unusedDatasets, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };
|