pptx-vanilla-viewer 2.13.0 → 2.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/dist/styles.css CHANGED
@@ -938,6 +938,15 @@
938
938
  }
939
939
  .pptxv-inspector-tab:hover { color: var(--pptx-foreground); background: var(--pptx-accent); }
940
940
  .pptxv-inspector-tab.is-active { background: var(--pptx-primary); color: var(--pptx-primary-foreground, #fff); }
941
+ /* Below this width, matches isDensePanelCompact()/MOBILE_BREAKPOINT (768) in
942
+ pptx-viewer-shared: getDensePanelTouchTargetPx(width) returns
943
+ MIN_TOUCH_TARGET_PX (44), so the Elements/Properties/Comments tab buttons
944
+ clear a touch-sized hit area. This binding's inspector pane has no inline
945
+ close button (its visibility is toggled elsewhere), so there is nothing
946
+ else to size here. */
947
+ @media (max-width: 767px) {
948
+ .pptxv-inspector-tab { min-height: 44px; }
949
+ }
941
950
  /* Elements tab: layer-order rows. */
942
951
  .pptxv-inspector-layer-list { display: flex; flex-direction: column; gap: 2px; }
943
952
  .pptxv-inspector-layer-row {
@@ -1318,6 +1327,28 @@
1318
1327
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
1319
1328
  }
1320
1329
 
1330
+ /* Touch target: matches MIN_TOUCH_TARGET_PX (44) from pptx-viewer-shared's
1331
+ render/responsive module, below MOBILE_BREAKPOINT (768). The `!important`
1332
+ is load-bearing: this button lives inside `.pptxv`, so it is also matched
1333
+ by css.ts's baseline `.pptxv :is(button, [role='button'])... { min-width:
1334
+ 24px; min-height: 24px; }`, whose chained :not() pseudo-classes give it
1335
+ higher specificity than a plain class selector. */
1336
+ @media (max-width: 767px) {
1337
+ .pptxv-inspector-deck-btn { min-height: 44px !important; }
1338
+ .pptxv-inspector-tab { min-height: 44px !important; }
1339
+ .pptxv-inspector-lock-btn { min-width: 44px !important; min-height: 44px !important; }
1340
+ /* `.pptxv-field-select-input` (controls-extra.ts's shared `makeSelectField`
1341
+ factory) backs many inspector <select> rows (Shape Type, ...), so fixing
1342
+ it once here reaches all of them. A <select>, not a <button>, so css.ts's
1343
+ button-only baseline does not apply and no `!important` is needed. */
1344
+ .pptxv-field-select-input { min-height: 44px; }
1345
+ /* Table style presets (table-section.ts): a 3-column gallery of named,
1346
+ individually-labelled preview tiles ("Medium 1", ...) - plenty of room
1347
+ per column to grow past its 40px desktop height, unlike a dense colour
1348
+ swatch grid, so it gets the WCAG target rather than an exemption. */
1349
+ .pptxv-table-preset-swatch { height: 44px !important; }
1350
+ }
1351
+
1321
1352
 
1322
1353
  /* ── Ribbon shell and React-aligned command row ─────────────────────────── */
1323
1354
  .pptxv-ribbon {
@@ -2288,6 +2319,21 @@
2288
2319
  cursor: pointer;
2289
2320
  }
2290
2321
  .pptxv-modal-danger-btn:hover { background: rgb(239 68 68 / 0.2); }
2322
+ /* Below this width, matches isDensePanelCompact()/MOBILE_BREAKPOINT (768) in
2323
+ pptx-viewer-shared: getDensePanelTouchTargetPx(width) returns
2324
+ MIN_TOUCH_TARGET_PX (44), so the header close button, the footer/danger
2325
+ buttons, the text inputs and the Create/Join mode-toggle tabs of every
2326
+ modal built on this shell (Share, Broadcast) clear a touch-sized hit area.
2327
+ The footer itself is already outside the panel's own scroll region (only
2328
+ .pptxv-modal-body scrolls, see above), so it stays visible without needing
2329
+ shouldStickyActionRow's position: sticky. */
2330
+ @media (max-width: 767px) {
2331
+ .pptxv-modal-close { width: 44px; height: 44px; }
2332
+ .pptxv-modal-btn { min-height: 44px; }
2333
+ .pptxv-modal-danger-btn { min-height: 44px; }
2334
+ .pptxv-modal-input { min-height: 44px; }
2335
+ .pptxv-share-tabs button { min-height: 44px; }
2336
+ }
2291
2337
 
2292
2338
  /* ── Share dialog: active-session status/details/connected-users ───────── */
2293
2339
  .pptxv-share-status-row { display: flex; align-items: center; gap: 8px; font-size: 13px; }
@@ -2915,7 +2961,7 @@
2915
2961
  .pptxv-mobile-comment { display: grid; gap: 6px; padding: 8px 0; border-bottom: 1px solid var(--pptx-border); }
2916
2962
  .pptxv-mobile-comment textarea, .pptxv-mobile-comment-add textarea { box-sizing: border-box; width: 100%; min-height: 58px; padding: 8px; border: 1px solid var(--pptx-border); border-radius: var(--pptx-radius); background: var(--pptx-background); color: var(--pptx-foreground); font: inherit; }
2917
2963
  .pptxv-mobile-comment-actions { display: flex; flex-wrap: wrap; gap: 6px; }
2918
- .pptxv-mobile-comment-actions button, .pptxv-mobile-comment-add button { min-height: 36px; padding: 6px 10px; border: 1px solid var(--pptx-border); border-radius: var(--pptx-radius); background: var(--pptx-muted); color: var(--pptx-foreground); }
2964
+ .pptxv-mobile-comment-actions button, .pptxv-mobile-comment-add button { min-height: 44px !important; padding: 6px 10px; border: 1px solid var(--pptx-border); border-radius: var(--pptx-radius); background: var(--pptx-muted); color: var(--pptx-foreground); }
2919
2965
  .pptxv-mobile-comment-add { display: grid; gap: 6px; padding-top: 10px; }
2920
2966
  .pptxv-mobile-slide-list button { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 6px; border: 1px solid var(--pptx-border); border-radius: 8px; background: var(--pptx-muted); color: inherit; text-align: left; }
2921
2967
  .pptxv-mobile-slide-list button.is-active { border-color: var(--pptx-primary); color: var(--pptx-primary); }
@@ -3042,7 +3088,19 @@
3042
3088
  .pptxv-sorter-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; overflow: auto; padding: 18px; } .pptxv-sorter-card { overflow: hidden; border: 2px solid var(--pptx-border); border-radius: 7px; background: var(--pptx-card); } .pptxv-sorter-card.is-current { border-color: var(--pptx-primary); } .pptxv-sorter-card.is-hidden { opacity: .5; } .pptxv-sorter-card > button { display: grid; width: 100%; min-height: 90px; place-items: center; border: 0; background: var(--pptx-muted); color: inherit; font-size: 22px; cursor: pointer; } .pptxv-sorter-card div { display: flex; gap: 3px; padding: 5px; } .pptxv-sorter-card div button { flex: 1; padding: 4px; border: 0; background: transparent; color: inherit; font-size: 9px; cursor: pointer; }
3043
3089
  .pptxv-custom-shows-active { display: flex; align-items: center; gap: 8px; } .pptxv-custom-shows-active select { flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--pptx-border); border-radius: 4px; background: var(--pptx-muted); color: inherit; }
3044
3090
  .pptxv-custom-shows article { display: grid; grid-template-columns: 1fr auto auto auto; gap: 6px; padding: 8px; border: 1px solid var(--pptx-border); border-radius: 6px; } .pptxv-custom-shows article > div { grid-column: 1 / -1; max-height: 140px; overflow: auto; }
3045
- @media (max-width: 767px) { .pptxv-parity-dialog { top: auto; bottom: 0; width: 100%; max-height: 88dvh; transform: translateX(-50%); border-radius: 16px 16px 0 0; } }
3091
+ @media (max-width: 767px) {
3092
+ .pptxv-parity-dialog { top: auto; bottom: 0; width: 100%; max-height: 88dvh; transform: translateX(-50%); border-radius: 16px 16px 0 0; }
3093
+ .pptxv-parity-header button { display: flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }
3094
+ /* Touch target: matches MIN_TOUCH_TARGET_PX (44) from pptx-viewer-shared's
3095
+ render/responsive module. The Print/Share/Sorter/etc "parity" dialogs
3096
+ share this shell (parity-dialog-shell.ts); the header close button was
3097
+ already sized, but the footer action buttons (Cancel/OK/Print) and any
3098
+ select dropdown were left at their mouse-sized padding. */
3099
+ .pptxv-parity-footer button { min-width: 44px; min-height: 44px; }
3100
+ .pptxv-parity-select select, .pptxv-custom-shows-active select { min-height: 44px; }
3101
+ .pptxv-parity-check, .pptxv-parity-range { min-height: 44px; }
3102
+ .pptxv-parity-tabs button { min-height: 44px; }
3103
+ }
3046
3104
  .pptxv-ole-edit-dialog { width: min(600px, calc(100vw - 32px)); }
3047
3105
  .pptxv-ole-edit-loading, .pptxv-ole-edit-empty { color: var(--pptx-muted-foreground); }
3048
3106
  .pptxv-ole-edit-error { color: var(--pptx-destructive); }
@@ -3055,6 +3113,15 @@
3055
3113
  .pptxv-ole-edit-paragraphs textarea { padding: 6px 8px; border: 1px solid var(--pptx-border); border-radius: 4px; background: var(--pptx-muted); color: inherit; resize: vertical; }
3056
3114
  .pptxv-ole-edit-deck-row { display: flex; flex-direction: column; gap: 4px; color: var(--pptx-muted-foreground); }
3057
3115
  .pptxv-ole-edit-deck-row input { padding: 6px 8px; border: 1px solid var(--pptx-border); border-radius: 4px; background: var(--pptx-muted); color: var(--pptx-foreground); }
3116
+ /* Touch target: matches MIN_TOUCH_TARGET_PX (44) from pptx-viewer-shared's
3117
+ render/responsive module, below MOBILE_BREAKPOINT (768). The workspace
3118
+ Comments pane's "Add Comment" button (comments-panel.ts) carries no class
3119
+ of its own; `!important` beats css.ts's baseline
3120
+ `.pptxv :is(button, [role='button'])... { min-height: 24px; }`, whose
3121
+ chained :not() pseudo-classes out-specificity a plain class selector. */
3122
+ @media (max-width: 767px) {
3123
+ .pptxv-workspace-list button, .pptxv-workspace-pane header button { min-height: 44px !important; }
3124
+ }
3058
3125
 
3059
3126
 
3060
3127
  /* ── Dialog shell override: the Options dialog is wider than parity dialogs ── */
@@ -3150,7 +3217,23 @@ label.pptxv-options-row { cursor: pointer; }
3150
3217
  opacity/pointer-events on mousemove; !important here is required to win
3151
3218
  over that inline style regardless of the JS auto-show timer. */
3152
3219
  .pptxv.pptxv-no-show-popup .pptxv-present-toolbar-wrap { opacity: 0 !important; pointer-events: none !important; }
3153
- @media (max-width: 767px) { .pptxv-options-body { flex-direction: column; } .pptxv-options-nav { flex-direction: row; width: 100%; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--pptx-border); } }
3220
+ @media (max-width: 767px) {
3221
+ .pptxv-options-body { flex-direction: column; }
3222
+ .pptxv-options-nav { flex-direction: row; width: 100%; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--pptx-border); }
3223
+ /* Matches isDensePanelCompact()/MOBILE_BREAKPOINT (768) in
3224
+ pptx-viewer-shared: getDensePanelTouchTargetPx(width) returns
3225
+ MIN_TOUCH_TARGET_PX (44). Every schema-driven control row (toggle /
3226
+ select / number / text, across every tab) gets a touch-sized hit area:
3227
+ the row itself (a <label> for a toggle, so enlarging it is enough there)
3228
+ and each select/text/number control. */
3229
+ .pptxv-options-row { min-height: 44px; }
3230
+ .pptxv-options-row select, .pptxv-options-row input[type='text'], .pptxv-options-row input[type='number'] { min-height: 44px; }
3231
+ /* The category rail's own tab buttons are discrete one-per-row controls
3232
+ too, so they get the same touch target as everything else in this
3233
+ dialog below the breakpoint - CLAUDE.md Rule 1 (React's SettingsDialog
3234
+ navBtnStyle already covers its own nav for the same reason). */
3235
+ .pptxv-options-nav button { min-height: 44px; }
3236
+ }
3154
3237
 
3155
3238
 
3156
3239
  /* Animations > Animation: the full 27-preset catalogue in three captioned
@@ -3357,6 +3440,12 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3357
3440
  min-width: 44px !important;
3358
3441
  min-height: 44px !important;
3359
3442
  }
3443
+ /* animation-panel-fields.ts's animSelect/animNumber (Entrance/Emphasis/Exit
3444
+ effect pickers, ...) carry no class of their own on the control. */
3445
+ .pptxv-inspector-animation select,
3446
+ .pptxv-inspector-animation input {
3447
+ min-height: 44px;
3448
+ }
3360
3449
  }
3361
3450
 
3362
3451
  /* ── Comments tab: threads, replies, edit-in-place ───────────────────── */
@@ -3435,7 +3524,7 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3435
3524
  .pptxv-action-return-row[hidden] { display: none; }
3436
3525
 
3437
3526
  /* ── Table style editor: touch target only ────────────────────────────
3438
- .pptxv-tse*/.pptxv-tsef* (table-style-editor.ts /
3527
+ .pptxv-tse and .pptxv-tsef classes (table-style-editor.ts /
3439
3528
  table-style-editor-fields.ts) otherwise carry no CSS at all in this
3440
3529
  binding (unstyled/browser-default buttons) - out of scope to redesign
3441
3530
  here, but the Bold/Italic/Underline toggles and the editor's own action
@@ -3447,6 +3536,13 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3447
3536
  min-width: 44px !important;
3448
3537
  min-height: 44px !important;
3449
3538
  }
3539
+ /* Action Settings section (action-section.ts): the trigger-type and
3540
+ custom-show <select>s carry no class of their own, so target them
3541
+ through the fieldset wrapper. !important is load-bearing (see
3542
+ css.ts's baseline .pptxv :is(button, [role='button'])... note above). */
3543
+ .pptxv-action-fieldset select {
3544
+ min-height: 44px !important;
3545
+ }
3450
3546
  }
3451
3547
 
3452
3548
 
@@ -3466,6 +3562,13 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3466
3562
  }
3467
3563
  .pptxv-quick-style:hover:not(:disabled) { outline: 2px solid var(--pptx-primary); outline-offset: -1px; }
3468
3564
  .pptxv-quick-style:disabled { opacity: 0.5; cursor: default; }
3565
+ /* Each preset is a discrete, individually-named action button (not a colour
3566
+ swatch), so it gets the shared WCAG touch target below the mobile
3567
+ breakpoint (768px, MOBILE_BREAKPOINT / getDensePanelTouchTargetPx in
3568
+ pptx-viewer-shared) rather than an exemption - CLAUDE.md Rule 2. */
3569
+ @media (max-width: 767px) {
3570
+ .pptxv-quick-style { height: 44px !important; min-width: 44px !important; }
3571
+ }
3469
3572
 
3470
3573
  /* ── 3D text ─────────────────────────────────────────────────────────── */
3471
3574
  .pptxv-text3d-options { display: grid; gap: 6px; }
@@ -3495,7 +3598,7 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3495
3598
  }
3496
3599
  .pptxv-chart-grid-btn:hover:not(:disabled) { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
3497
3600
  .pptxv-chart-grid-table { width: 100%; border-collapse: collapse; font-size: 11px; }
3498
- .pptxv-chart-grid-table th, .pptxv-chart-grid-table td { padding: 1px; }
3601
+ .pptxv-chart-grid-table th, .pptxv-chart-grid-table td { padding: 1px; min-width: 72px; }
3499
3602
  .pptxv-chart-grid-table th { font-weight: 400; }
3500
3603
  .pptxv-chart-grid-table :is(th, td) { display: table-cell; white-space: nowrap; }
3501
3604
  .pptxv-chart-grid-cell {
@@ -3523,6 +3626,23 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3523
3626
  cursor: pointer;
3524
3627
  }
3525
3628
  .pptxv-chart-grid-remove:hover { color: var(--pptx-destructive); }
3629
+ /* Below this width, matches isDensePanelCompact()/MOBILE_BREAKPOINT (768) in
3630
+ pptx-viewer-shared: getDenseGridLayoutPlan(width) returns
3631
+ stickyFirstColumn: true, minCellWidthPx: 64, and
3632
+ getDensePanelTouchTargetPx(width) returns MIN_TOUCH_TARGET_PX (44). Pins
3633
+ the category-label column so a value scrolled into view still reads
3634
+ against its row, and gives the add/remove controls a touch-sized hit area. */
3635
+ @media (max-width: 767px) {
3636
+ .pptxv-chart-grid-table th, .pptxv-chart-grid-table td { min-width: 64px; }
3637
+ .pptxv-chart-grid-table th:first-child, .pptxv-chart-grid-table td:first-child {
3638
+ position: sticky;
3639
+ left: 0;
3640
+ z-index: 1;
3641
+ background: var(--pptx-background);
3642
+ }
3643
+ .pptxv-chart-grid-table thead th:first-child { z-index: 2; }
3644
+ .pptxv-chart-grid-btn, .pptxv-chart-grid-remove { min-width: 44px !important; min-height: 44px !important; }
3645
+ }
3526
3646
 
3527
3647
  /* ── Table data grid ─────────────────────────────────────────────────── */
3528
3648
  .pptxv-table-grid-header { display: flex; align-items: center; justify-content: space-between; gap: 4px; }
@@ -3549,7 +3669,7 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3549
3669
  align-items: center;
3550
3670
  justify-content: center;
3551
3671
  gap: 2px;
3552
- min-width: 0;
3672
+ min-width: 72px;
3553
3673
  margin: -1px 0 0 -1px;
3554
3674
  padding: 1px 3px;
3555
3675
  border: 1px solid var(--pptx-border);
@@ -3557,11 +3677,11 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3557
3677
  color: var(--pptx-muted-foreground);
3558
3678
  white-space: nowrap;
3559
3679
  }
3560
- .pptxv-table-grid-gutter { flex: 0 0 38px; }
3680
+ .pptxv-table-grid-gutter { flex: 0 0 38px; min-width: 38px; }
3561
3681
  .pptxv-table-grid-cell {
3562
3682
  display: flex;
3563
3683
  flex: 1 1 56px;
3564
- min-width: 0;
3684
+ min-width: 72px;
3565
3685
  margin: -1px 0 0 -1px;
3566
3686
  padding: 1px;
3567
3687
  border: 1px solid var(--pptx-border);
@@ -3590,6 +3710,24 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3590
3710
  }
3591
3711
  .pptxv-table-grid-remove[hidden] { display: none; }
3592
3712
  .pptxv-table-grid-remove:hover { color: var(--pptx-destructive); }
3713
+ /* Below this width, matches isDensePanelCompact()/MOBILE_BREAKPOINT (768) in
3714
+ pptx-viewer-shared: getDenseGridLayoutPlan(width) returns
3715
+ stickyFirstColumn: true, minCellWidthPx: 64, and
3716
+ getDensePanelTouchTargetPx(width) returns MIN_TOUCH_TARGET_PX (44). Pins
3717
+ the row-number gutter so a cell scrolled into view still reads against its
3718
+ row, and gives the add/remove controls a touch-sized hit area. */
3719
+ @media (max-width: 767px) {
3720
+ .pptxv-table-grid-head:not(.pptxv-table-grid-gutter), .pptxv-table-grid-cell { min-width: 64px; }
3721
+ .pptxv-table-grid-gutter {
3722
+ min-width: 38px;
3723
+ position: sticky;
3724
+ left: 0;
3725
+ z-index: 1;
3726
+ background: var(--pptx-muted);
3727
+ }
3728
+ .pptxv-table-grid-btn { min-width: 44px !important; min-height: 44px !important; }
3729
+ .pptxv-table-grid-remove { min-width: 44px !important; min-height: 44px !important; }
3730
+ }
3593
3731
 
3594
3732
  /* ── Media trim timeline ─────────────────────────────────────────────── */
3595
3733
  .pptxv-media-timeline { display: grid; gap: 2px; margin: 6px 0; }
@@ -3782,6 +3920,43 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3782
3920
  }
3783
3921
  .pptxv-image-alt-input:focus-visible { outline: 2px solid var(--pptx-ring); outline-offset: -1px; }
3784
3922
 
3923
+ /* chart-exhaustive-controls.ts's field()/tokenSelect() factory backs dozens
3924
+ of chart/table controls (Chart type, Grouping, Alignment, ...) and carried
3925
+ no class of its own, so a touch-target fix here reaches all of them. */
3926
+ @media (max-width: 767px) {
3927
+ .pptxv-exhaustive-field-control { min-height: 44px; min-width: 44px; }
3928
+ /* text-effects-controls.ts's own local field() helper (Transform warp
3929
+ select, ...) carries no class of its own either; target it through its
3930
+ section container. */
3931
+ .pptxv-inspector-text-effects select,
3932
+ .pptxv-inspector-text-effects input {
3933
+ min-height: 44px;
3934
+ }
3935
+ /* Several other inspector sub-panels' own local field() helpers
3936
+ (chart-filtered-series-section.ts, connector-arrow-controls.ts,
3937
+ table-cell-formatting.ts, shape-effects-controls.ts) carry no class of
3938
+ their own on the control either; same fix, through each section's own
3939
+ container class. Buttons get !important (css.ts's baseline, see the
3940
+ .pptxv-quick-style rule above); selects/inputs do not need it. */
3941
+ .pptxv-chart-filters select, .pptxv-chart-filters input,
3942
+ .pptxv-inspector-connector-arrows select, .pptxv-inspector-connector-arrows input,
3943
+ .pptxv-inspector-table-cell select, .pptxv-inspector-table-cell input,
3944
+ .pptxv-inspector-table-cell-fill select, .pptxv-inspector-table-cell-fill input,
3945
+ .pptxv-inspector-shape-effects select, .pptxv-inspector-shape-effects input {
3946
+ min-height: 44px;
3947
+ }
3948
+ .pptxv-chart-filters button,
3949
+ .pptxv-inspector-connector-arrows button,
3950
+ .pptxv-inspector-table-cell button,
3951
+ .pptxv-inspector-table-cell-fill button,
3952
+ .pptxv-inspector-table-structure button,
3953
+ .pptxv-chart-usershapes button,
3954
+ .pptxv-inspector-shape-effects button {
3955
+ min-width: 44px !important;
3956
+ min-height: 44px !important;
3957
+ }
3958
+ }
3959
+
3785
3960
 
3786
3961
  .pptxv-account { display: flex; flex-direction: column; gap: 28px; max-width: 640px; margin-top: 24px; }
3787
3962
  .pptxv-account-section { padding: 20px; border: 1px solid var(--pptx-border); border-radius: 8px; background: var(--pptx-card); color: var(--pptx-card-foreground); }
@@ -4096,6 +4271,9 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
4096
4271
  box-shadow: 0 -12px 36px rgb(0 0 0 / 0.35);
4097
4272
  }
4098
4273
  .pptxv.pptxv-presenting .pptxv-ai-panel { display: none; }
4274
+ /* Touch target: matches MIN_TOUCH_TARGET_PX (44) from pptx-viewer-shared's
4275
+ render/responsive module. */
4276
+ .pptxv-ai-close { min-width: 44px !important; min-height: 44px !important; }
4099
4277
  }
4100
4278
 
4101
4279
 
@@ -4227,6 +4405,11 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
4227
4405
  font-size: 0.625rem;
4228
4406
  color: var(--pptx-muted-foreground);
4229
4407
  }
4408
+ /* Touch target: matches MIN_TOUCH_TARGET_PX (44) from pptx-viewer-shared's
4409
+ render/responsive module, below MOBILE_BREAKPOINT (768). */
4410
+ @media (max-width: 767px) {
4411
+ .pptxv-ai-chats, .pptxv-ai-history-new, .pptxv-ai-history-delete { min-width: 44px !important; min-height: 44px !important; }
4412
+ }
4230
4413
 
4231
4414
 
4232
4415
  /* ── Focused-target bar ───────────────────────────────────────────────── */
@@ -4296,6 +4479,11 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
4296
4479
  cursor: pointer;
4297
4480
  }
4298
4481
  .pptxv-ai-focus-merge svg { width: 12px; height: 12px; }
4482
+ /* Touch target: matches MIN_TOUCH_TARGET_PX (44) from pptx-viewer-shared's
4483
+ render/responsive module, below MOBILE_BREAKPOINT (768). */
4484
+ @media (max-width: 767px) {
4485
+ .pptxv-ai-focus-btn, .pptxv-ai-focus-merge, .pptxv-ai-focus-pick-done { min-width: 44px !important; min-height: 44px !important; }
4486
+ }
4299
4487
 
4300
4488
  /* ── Pick-mode banner ─────────────────────────────────────────────────── */
4301
4489
  .pptxv-ai-focus-pick {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-vanilla-viewer",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "Zero-framework PowerPoint viewer and editor: render, edit, present, and export PPTX slides with plain DOM, no React/Vue/Angular required.",
5
5
  "keywords": [
6
6
  "javascript",
@@ -61,10 +61,12 @@
61
61
  "jspdf": "^4.2.1",
62
62
  "jszip": "^3.10.2",
63
63
  "lucide": "^1.43.0",
64
+ "opentype.js": "^2.0.0",
64
65
  "pptx-viewer-mcp": "^2.5.0"
65
66
  },
66
67
  "devDependencies": {
67
68
  "@types/dompurify": "^3.2.0",
69
+ "@types/opentype.js": "^1.3.10",
68
70
  "happy-dom": "^20.14.0",
69
71
  "tsdown": "^0.23.0",
70
72
  "tsup": "^8.5.1",
@@ -1 +0,0 @@
1
- 'use strict';var chunkDFG2BX27_cjs=require('./chunk-DFG2BX27.cjs');require('./chunk-B5PFHICE.cjs');function K(o){let{doc:t,t:n,controller:i}=o,a=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-focus"),h=(p,m,l)=>{let s=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-focus-btn");return s.type="button",s.title=m,s.setAttribute("aria-label",m),s.appendChild(chunkDFG2BX27_cjs.po(t,p)),s.addEventListener("click",l),s},x=()=>{a.replaceChildren();let p=i.getEffectiveTargets(),m=i.hasPicks(),l=i.isPinned(),s=i.isPicking(),g=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-focus-row"),f=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-focus-label");f.textContent=n("pptx.ai.focusScope"),g.appendChild(f);for(let r of chunkDFG2BX27_cjs.Rn(p,o.getSlides())){let b=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-focus-chip");(m||l)&&b.classList.add("is-strong"),b.title=r.title,b.textContent=r.label,g.appendChild(b);}if(l){let r=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-focus-pinned");r.textContent=n("pptx.ai.pinnedFocus"),g.appendChild(r);}let C=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-focus-actions"),d=chunkDFG2BX27_cjs.Sn(p,o.getSlides());if(d){let r=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-focus-merge");r.type="button",r.append(chunkDFG2BX27_cjs.po(t,"git-merge"),t.createTextNode(n("pptx.ai.mergeSelectedTables"))),r.addEventListener("click",()=>o.onSendDirective(chunkDFG2BX27_cjs.Tn(d.slideIndex,d.elementIdA,d.elementIdB))),C.appendChild(r);}let y=h("crosshair",n("pptx.ai.pickElement"),()=>s?i.stopPicking():i.startPicking());if(y.setAttribute("aria-pressed",String(s)),y.classList.toggle("is-active",s),C.appendChild(y),m?C.appendChild(h("close",n("pptx.ai.pickClear"),()=>i.clearPicks())):l?C.appendChild(h("pin-off",n("pptx.ai.clearFocus"),()=>i.clearPinnedFocus())):C.appendChild(h("pin",n("pptx.ai.pinFocus"),()=>i.pinFocus())),g.appendChild(C),a.appendChild(g),s){let r=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-focus-pick"),b=chunkDFG2BX27_cjs.po(t,"crosshair");b.classList.add("pptxv-ai-focus-pick-icon");let k=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-focus-pick-hint");k.textContent=n("pptx.ai.pickElementHint");let T=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-focus-pick-done");T.type="button",T.textContent=n("pptx.ai.pickDone"),T.addEventListener("click",()=>i.stopPicking()),r.append(b,k,T),a.appendChild(r);}},c=i.subscribe(x);return x(),{el:a,destroy(){c(),a.remove();}}}function O(o){let{doc:t,t:n}=o,i=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-chats");i.type="button",i.append(chunkDFG2BX27_cjs.po(t,"history"),t.createTextNode(n("pptx.ai.chats")));let a=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-history");a.hidden=true;let h=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-history-head"),x=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-history-title");x.textContent=n("pptx.ai.historyTitle");let c=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-history-new");c.type="button",c.append(chunkDFG2BX27_cjs.po(t,"plus"),t.createTextNode(n("pptx.ai.newChat"))),h.append(x,c);let p=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-history-body"),m=chunkDFG2BX27_cjs.co(t,"p","pptxv-ai-history-hint");m.textContent=n("pptx.ai.historyHint"),a.append(h,p,m);let l=chunkDFG2BX27_cjs.Vn({deckId:o.deckId,store:o.store,getMessages:o.getMessages,setMessages:o.setMessages,untitledLabel:n("pptx.ai.untitledChat"),onChatsChanged:()=>s()});function s(){p.replaceChildren();let f=l.chats();if(f.length===0){let d=chunkDFG2BX27_cjs.co(t,"p","pptxv-ai-history-empty");d.textContent=n("pptx.ai.historyEmpty"),p.appendChild(d);return}let C=chunkDFG2BX27_cjs.co(t,"ul","pptxv-ai-history-list");for(let d of f){let y=chunkDFG2BX27_cjs.co(t,"li","pptxv-ai-history-row"),r=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-history-resume");r.type="button",r.classList.toggle("is-active",d.id===l.activeChatId());let b=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-history-text"),k=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-history-name");k.textContent=d.title||n("pptx.ai.untitledChat");let T=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-history-meta");T.textContent=n("pptx.ai.messageCount",{count:d.messageCount}),b.append(k,T),r.append(chunkDFG2BX27_cjs.po(t,"comment"),b),r.addEventListener("click",()=>{l.resumeChat(d.id),a.hidden=true;});let P=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-history-delete");P.type="button",P.title=n("pptx.ai.deleteChat"),P.setAttribute("aria-label",n("pptx.ai.deleteChat")),P.appendChild(chunkDFG2BX27_cjs.po(t,"trash")),P.addEventListener("click",()=>{l.deleteChat(d.id);}),y.append(r,P),C.appendChild(y);}p.appendChild(C);}s(),i.addEventListener("click",()=>{a.hidden=!a.hidden;}),c.addEventListener("click",()=>{l.newChat(),a.hidden=true;});let g=f=>{a.hidden||!(f.target instanceof Node)||!a.contains(f.target)&&!i.contains(f.target)&&(a.hidden=true);};return t.addEventListener("mousedown",g),{button:i,el:a,notifyMessagesChanged:()=>l.notifyMessagesChanged(),destroy(){t.removeEventListener("mousedown",g),l.dispose(),i.remove(),a.remove();}}}var _={view:"eye",text:"text-box",shape:"shapes",theme:"font-color",table:"table",slide:"layout",chart:"chart",move:"move-right",delete:"trash",search:"search",nav:"move-right",animation:"play",notes:"sticky-note",tool:"wrench"};function W(o,t,n){let i=t.state==="output-error",a=t.state==="output-available",h=!i&&!a,x=chunkDFG2BX27_cjs._n(t.toolName,t.input,h?"present":"past"),c=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-tool"),p=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-tool-head"),m=chunkDFG2BX27_cjs.po(o,_[x.icon]??"wrench");m.classList.add("pptxv-ai-tool-icon");let l=chunkDFG2BX27_cjs.co(o,"span","pptxv-ai-tool-name");l.textContent=x.label;let s=chunkDFG2BX27_cjs.co(o,"span","pptxv-ai-tool-state");if(i?(s.classList.add("is-error"),s.append(chunkDFG2BX27_cjs.po(o,"alert"),o.createTextNode(n("pptx.ai.toolFailed")))):a?(s.classList.add("is-done"),s.append(chunkDFG2BX27_cjs.po(o,"check"),o.createTextNode(n("pptx.ai.toolDone")))):(s.classList.add("is-running"),s.textContent=n("pptx.ai.toolRunning")),p.append(m,l,s),c.appendChild(p),i&&t.errorText){let f=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-tool-error");f.textContent=t.errorText,c.appendChild(f);}let g=chunkDFG2BX27_cjs.Zn(t.input);if(g){let f=chunkDFG2BX27_cjs.co(o,"details","pptxv-ai-tool-details"),C=chunkDFG2BX27_cjs.co(o,"summary");C.textContent=n("pptx.ai.toolDetails");let d=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-tool-raw");d.textContent=`${chunkDFG2BX27_cjs.Yn(t.toolName)}: ${g}`,f.append(C,d),c.appendChild(f);}return c}function q(o,t,n,i){t.replaceChildren();for(let a of n){if(a.role==="system")continue;let h=a.role==="user",x=chunkDFG2BX27_cjs.Nn(a);if(x.length===0&&!h)continue;let c=chunkDFG2BX27_cjs.co(o,"div",`pptxv-ai-msg pptxv-ai-msg-${a.role}`),p=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-msg-avatar");p.setAttribute("aria-label",i(h?"pptx.ai.you":"pptx.ai.assistant")),p.appendChild(chunkDFG2BX27_cjs.po(o,h?"comment":"sparkles"));let m=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-msg-body");for(let l of x)if(l.kind==="text"){let s=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-msg-text");s.textContent=l.text,m.appendChild(s);}else m.appendChild(W(o,l,i));c.append(p,m),t.appendChild(c);}}function G(o,t,n,i,a){if(t.replaceChildren(),t.hidden=n.length===0,n.length===0)return;let h=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-proposals-header"),x=chunkDFG2BX27_cjs.co(o,"span","pptxv-ai-proposals-title");if(x.textContent=i("pptx.ai.pendingChanges",{count:n.length}),h.appendChild(x),n.length>1){let c=chunkDFG2BX27_cjs.co(o,"button","pptxv-ai-proposal-btn is-accept-all");c.type="button",c.textContent=i("pptx.ai.acceptAll"),c.addEventListener("click",()=>a.acceptAll()),h.appendChild(c);}t.appendChild(h);for(let c of n)t.appendChild(tt(o,c,i,a));}function tt(o,t,n,i){let a=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-proposal");a.dataset.proposalId=t.id;let h=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-proposal-eyebrow");h.textContent=n("pptx.ai.proposedChange"),a.appendChild(h);let x=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-proposal-label");if(x.textContent=t.label,a.appendChild(x),t.summary.length>0){let l=chunkDFG2BX27_cjs.co(o,"ul","pptxv-ai-proposal-summary");for(let s of t.summary){let g=chunkDFG2BX27_cjs.co(o,"li");g.textContent=chunkDFG2BX27_cjs.Kn(s),l.appendChild(g);}a.appendChild(l);}let c=chunkDFG2BX27_cjs.co(o,"div","pptxv-ai-proposal-actions"),p=chunkDFG2BX27_cjs.co(o,"button","pptxv-ai-proposal-btn is-accept");p.type="button",p.append(chunkDFG2BX27_cjs.po(o,"check"),o.createTextNode(n("pptx.ai.accept"))),p.addEventListener("click",()=>i.accept(t.id));let m=chunkDFG2BX27_cjs.co(o,"button","pptxv-ai-proposal-btn is-reject");return m.type="button",m.append(chunkDFG2BX27_cjs.po(o,"close"),o.createTextNode(n("pptx.ai.reject"))),m.addEventListener("click",()=>i.reject(t.id)),c.append(p,m),a.appendChild(c),a}async function wt(o){let{doc:t,host:n,t:i}=o;n.replaceChildren();let a=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-header"),h=chunkDFG2BX27_cjs.co(t,"span","pptxv-ai-title");h.textContent=i("pptx.ai.title");let x=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-close");x.type="button",x.title=i("pptx.ai.close"),x.setAttribute("aria-label",i("pptx.ai.close")),x.appendChild(chunkDFG2BX27_cjs.po(t,"close")),x.addEventListener("click",()=>o.onClose?.()),a.append(chunkDFG2BX27_cjs.po(t,"sparkles"),h,x);let c,p=o.controller,m=p?K({doc:t,t:i,controller:p,getSlides:()=>o.bridge.getSlides(),onSendDirective:u=>{c?.sendMessage(u);}}):null,l=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-messages");l.setAttribute("role","log"),l.setAttribute("aria-live","polite");let s=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-empty");s.textContent=i("pptx.ai.emptyHint"),l.appendChild(s);let g=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-proposals");g.hidden=true;let f=chunkDFG2BX27_cjs.co(t,"div","pptxv-ai-error");f.setAttribute("role","alert"),f.hidden=true;let C=chunkDFG2BX27_cjs.co(t,"form","pptxv-ai-composer"),d=chunkDFG2BX27_cjs.co(t,"textarea","pptxv-ai-input");d.rows=2,d.placeholder=i("pptx.ai.placeholder"),d.setAttribute("aria-label",i("pptx.ai.placeholder"));let y=chunkDFG2BX27_cjs.co(t,"button","pptxv-ai-send");y.type="submit",y.setAttribute("aria-label",i("pptx.ai.send")),y.appendChild(chunkDFG2BX27_cjs.po(t,"send")),C.append(d,y),n.append(a,...m?[m.el]:[],l,g,f,C);try{c=await(o.createChat??chunkDFG2BX27_cjs.Wn)({bridge:o.bridge,config:o.config});}catch{return s.textContent=i("pptx.ai.unavailableTitle"),d.disabled=true,y.disabled=true,m?.destroy(),{destroy:()=>n.replaceChildren()}}let r=c,b=O({doc:t,t:i,deckId:chunkDFG2BX27_cjs.Un(o.bridge),store:o.historyStore,getMessages:()=>r.getSnapshot().messages,setMessages:u=>r.setMessages(u)});a.insertBefore(b.button,x),n.appendChild(b.el);let k=r.subscribe(()=>b.notifyMessagesChanged()),T=new Set,P=u=>{if(!p)return;let A=u.messages.flatMap(Y=>chunkDFG2BX27_cjs.Nn(Y).filter(Z=>Z.kind==="tool")).at(-1);if(!A||A.kind!=="tool"||A.state==="input-streaming"||T.has(A.toolCallId))return;T.add(A.toolCallId);let L=chunkDFG2BX27_cjs.$n(A.toolName,A.input);L&&L.slideIndex!==void 0&&o.goToSlide?.(L.slideIndex),p.flashToolTarget(L);},M=u=>{q(t,l,u.messages,i),s.hidden=u.messages.length>0,u.messages.length===0&&l.appendChild(s),G(t,g,r.proposals.list(),i,{accept:A=>{p?.flashToolTarget(null),r.proposals.apply(A),M(r.getSnapshot());},reject:A=>{r.proposals.revert(A),M(r.getSnapshot());},acceptAll:()=>{p?.flashToolTarget(null),r.proposals.acceptAll(),M(r.getSnapshot());}});let w=u.status==="submitted"||u.status==="streaming";n.classList.toggle("is-busy",w),y.setAttribute("aria-label",i(w?"pptx.ai.stop":"pptx.ai.send")),f.hidden=!u.error,f.textContent=u.error?i("pptx.ai.errorPrefix"):"",l.scrollTop=l.scrollHeight,P(u);},S=()=>{if(n.classList.contains("is-busy")){r.stop();return}let u=d.value.trim();u&&(d.value="",r.sendMessage(u));};C.addEventListener("submit",u=>{u.preventDefault(),S();}),d.addEventListener("keydown",u=>{u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),S());});let I=p?.getPrefill().nonce??0,J=()=>{if(!p)return;let u=p.getPrefill();u.nonce!==I&&(I=u.nonce,d.value=u.text,d.focus());},Q=p?.subscribe(J),X=r.subscribe(M);return M(r.getSnapshot()),{changeAnimator:r.changeAnimator,destroy(){X(),k(),b.destroy(),Q?.(),m?.destroy(),n.replaceChildren();}}}exports.createAiPanel=wt;
@@ -1 +0,0 @@
1
- import {co,po,Wn,Un,Vn,Nn,$n,Rn,Sn,Tn,_n,Zn,Yn,Kn}from'./chunk-WXSJURM4.js';import'./chunk-62D2TNHX.js';function K(o){let{doc:t,t:n,controller:i}=o,a=co(t,"div","pptxv-ai-focus"),h=(p,m,l)=>{let s=co(t,"button","pptxv-ai-focus-btn");return s.type="button",s.title=m,s.setAttribute("aria-label",m),s.appendChild(po(t,p)),s.addEventListener("click",l),s},x=()=>{a.replaceChildren();let p=i.getEffectiveTargets(),m=i.hasPicks(),l=i.isPinned(),s=i.isPicking(),g=co(t,"div","pptxv-ai-focus-row"),f=co(t,"span","pptxv-ai-focus-label");f.textContent=n("pptx.ai.focusScope"),g.appendChild(f);for(let r of Rn(p,o.getSlides())){let b=co(t,"span","pptxv-ai-focus-chip");(m||l)&&b.classList.add("is-strong"),b.title=r.title,b.textContent=r.label,g.appendChild(b);}if(l){let r=co(t,"span","pptxv-ai-focus-pinned");r.textContent=n("pptx.ai.pinnedFocus"),g.appendChild(r);}let C=co(t,"div","pptxv-ai-focus-actions"),d=Sn(p,o.getSlides());if(d){let r=co(t,"button","pptxv-ai-focus-merge");r.type="button",r.append(po(t,"git-merge"),t.createTextNode(n("pptx.ai.mergeSelectedTables"))),r.addEventListener("click",()=>o.onSendDirective(Tn(d.slideIndex,d.elementIdA,d.elementIdB))),C.appendChild(r);}let y=h("crosshair",n("pptx.ai.pickElement"),()=>s?i.stopPicking():i.startPicking());if(y.setAttribute("aria-pressed",String(s)),y.classList.toggle("is-active",s),C.appendChild(y),m?C.appendChild(h("close",n("pptx.ai.pickClear"),()=>i.clearPicks())):l?C.appendChild(h("pin-off",n("pptx.ai.clearFocus"),()=>i.clearPinnedFocus())):C.appendChild(h("pin",n("pptx.ai.pinFocus"),()=>i.pinFocus())),g.appendChild(C),a.appendChild(g),s){let r=co(t,"div","pptxv-ai-focus-pick"),b=po(t,"crosshair");b.classList.add("pptxv-ai-focus-pick-icon");let k=co(t,"span","pptxv-ai-focus-pick-hint");k.textContent=n("pptx.ai.pickElementHint");let T=co(t,"button","pptxv-ai-focus-pick-done");T.type="button",T.textContent=n("pptx.ai.pickDone"),T.addEventListener("click",()=>i.stopPicking()),r.append(b,k,T),a.appendChild(r);}},c=i.subscribe(x);return x(),{el:a,destroy(){c(),a.remove();}}}function O(o){let{doc:t,t:n}=o,i=co(t,"button","pptxv-ai-chats");i.type="button",i.append(po(t,"history"),t.createTextNode(n("pptx.ai.chats")));let a=co(t,"div","pptxv-ai-history");a.hidden=true;let h=co(t,"div","pptxv-ai-history-head"),x=co(t,"span","pptxv-ai-history-title");x.textContent=n("pptx.ai.historyTitle");let c=co(t,"button","pptxv-ai-history-new");c.type="button",c.append(po(t,"plus"),t.createTextNode(n("pptx.ai.newChat"))),h.append(x,c);let p=co(t,"div","pptxv-ai-history-body"),m=co(t,"p","pptxv-ai-history-hint");m.textContent=n("pptx.ai.historyHint"),a.append(h,p,m);let l=Vn({deckId:o.deckId,store:o.store,getMessages:o.getMessages,setMessages:o.setMessages,untitledLabel:n("pptx.ai.untitledChat"),onChatsChanged:()=>s()});function s(){p.replaceChildren();let f=l.chats();if(f.length===0){let d=co(t,"p","pptxv-ai-history-empty");d.textContent=n("pptx.ai.historyEmpty"),p.appendChild(d);return}let C=co(t,"ul","pptxv-ai-history-list");for(let d of f){let y=co(t,"li","pptxv-ai-history-row"),r=co(t,"button","pptxv-ai-history-resume");r.type="button",r.classList.toggle("is-active",d.id===l.activeChatId());let b=co(t,"span","pptxv-ai-history-text"),k=co(t,"span","pptxv-ai-history-name");k.textContent=d.title||n("pptx.ai.untitledChat");let T=co(t,"span","pptxv-ai-history-meta");T.textContent=n("pptx.ai.messageCount",{count:d.messageCount}),b.append(k,T),r.append(po(t,"comment"),b),r.addEventListener("click",()=>{l.resumeChat(d.id),a.hidden=true;});let P=co(t,"button","pptxv-ai-history-delete");P.type="button",P.title=n("pptx.ai.deleteChat"),P.setAttribute("aria-label",n("pptx.ai.deleteChat")),P.appendChild(po(t,"trash")),P.addEventListener("click",()=>{l.deleteChat(d.id);}),y.append(r,P),C.appendChild(y);}p.appendChild(C);}s(),i.addEventListener("click",()=>{a.hidden=!a.hidden;}),c.addEventListener("click",()=>{l.newChat(),a.hidden=true;});let g=f=>{a.hidden||!(f.target instanceof Node)||!a.contains(f.target)&&!i.contains(f.target)&&(a.hidden=true);};return t.addEventListener("mousedown",g),{button:i,el:a,notifyMessagesChanged:()=>l.notifyMessagesChanged(),destroy(){t.removeEventListener("mousedown",g),l.dispose(),i.remove(),a.remove();}}}var _={view:"eye",text:"text-box",shape:"shapes",theme:"font-color",table:"table",slide:"layout",chart:"chart",move:"move-right",delete:"trash",search:"search",nav:"move-right",animation:"play",notes:"sticky-note",tool:"wrench"};function W(o,t,n){let i=t.state==="output-error",a=t.state==="output-available",h=!i&&!a,x=_n(t.toolName,t.input,h?"present":"past"),c=co(o,"div","pptxv-ai-tool"),p=co(o,"div","pptxv-ai-tool-head"),m=po(o,_[x.icon]??"wrench");m.classList.add("pptxv-ai-tool-icon");let l=co(o,"span","pptxv-ai-tool-name");l.textContent=x.label;let s=co(o,"span","pptxv-ai-tool-state");if(i?(s.classList.add("is-error"),s.append(po(o,"alert"),o.createTextNode(n("pptx.ai.toolFailed")))):a?(s.classList.add("is-done"),s.append(po(o,"check"),o.createTextNode(n("pptx.ai.toolDone")))):(s.classList.add("is-running"),s.textContent=n("pptx.ai.toolRunning")),p.append(m,l,s),c.appendChild(p),i&&t.errorText){let f=co(o,"div","pptxv-ai-tool-error");f.textContent=t.errorText,c.appendChild(f);}let g=Zn(t.input);if(g){let f=co(o,"details","pptxv-ai-tool-details"),C=co(o,"summary");C.textContent=n("pptx.ai.toolDetails");let d=co(o,"div","pptxv-ai-tool-raw");d.textContent=`${Yn(t.toolName)}: ${g}`,f.append(C,d),c.appendChild(f);}return c}function q(o,t,n,i){t.replaceChildren();for(let a of n){if(a.role==="system")continue;let h=a.role==="user",x=Nn(a);if(x.length===0&&!h)continue;let c=co(o,"div",`pptxv-ai-msg pptxv-ai-msg-${a.role}`),p=co(o,"div","pptxv-ai-msg-avatar");p.setAttribute("aria-label",i(h?"pptx.ai.you":"pptx.ai.assistant")),p.appendChild(po(o,h?"comment":"sparkles"));let m=co(o,"div","pptxv-ai-msg-body");for(let l of x)if(l.kind==="text"){let s=co(o,"div","pptxv-ai-msg-text");s.textContent=l.text,m.appendChild(s);}else m.appendChild(W(o,l,i));c.append(p,m),t.appendChild(c);}}function G(o,t,n,i,a){if(t.replaceChildren(),t.hidden=n.length===0,n.length===0)return;let h=co(o,"div","pptxv-ai-proposals-header"),x=co(o,"span","pptxv-ai-proposals-title");if(x.textContent=i("pptx.ai.pendingChanges",{count:n.length}),h.appendChild(x),n.length>1){let c=co(o,"button","pptxv-ai-proposal-btn is-accept-all");c.type="button",c.textContent=i("pptx.ai.acceptAll"),c.addEventListener("click",()=>a.acceptAll()),h.appendChild(c);}t.appendChild(h);for(let c of n)t.appendChild(tt(o,c,i,a));}function tt(o,t,n,i){let a=co(o,"div","pptxv-ai-proposal");a.dataset.proposalId=t.id;let h=co(o,"div","pptxv-ai-proposal-eyebrow");h.textContent=n("pptx.ai.proposedChange"),a.appendChild(h);let x=co(o,"div","pptxv-ai-proposal-label");if(x.textContent=t.label,a.appendChild(x),t.summary.length>0){let l=co(o,"ul","pptxv-ai-proposal-summary");for(let s of t.summary){let g=co(o,"li");g.textContent=Kn(s),l.appendChild(g);}a.appendChild(l);}let c=co(o,"div","pptxv-ai-proposal-actions"),p=co(o,"button","pptxv-ai-proposal-btn is-accept");p.type="button",p.append(po(o,"check"),o.createTextNode(n("pptx.ai.accept"))),p.addEventListener("click",()=>i.accept(t.id));let m=co(o,"button","pptxv-ai-proposal-btn is-reject");return m.type="button",m.append(po(o,"close"),o.createTextNode(n("pptx.ai.reject"))),m.addEventListener("click",()=>i.reject(t.id)),c.append(p,m),a.appendChild(c),a}async function wt(o){let{doc:t,host:n,t:i}=o;n.replaceChildren();let a=co(t,"div","pptxv-ai-header"),h=co(t,"span","pptxv-ai-title");h.textContent=i("pptx.ai.title");let x=co(t,"button","pptxv-ai-close");x.type="button",x.title=i("pptx.ai.close"),x.setAttribute("aria-label",i("pptx.ai.close")),x.appendChild(po(t,"close")),x.addEventListener("click",()=>o.onClose?.()),a.append(po(t,"sparkles"),h,x);let c,p=o.controller,m=p?K({doc:t,t:i,controller:p,getSlides:()=>o.bridge.getSlides(),onSendDirective:u=>{c?.sendMessage(u);}}):null,l=co(t,"div","pptxv-ai-messages");l.setAttribute("role","log"),l.setAttribute("aria-live","polite");let s=co(t,"div","pptxv-ai-empty");s.textContent=i("pptx.ai.emptyHint"),l.appendChild(s);let g=co(t,"div","pptxv-ai-proposals");g.hidden=true;let f=co(t,"div","pptxv-ai-error");f.setAttribute("role","alert"),f.hidden=true;let C=co(t,"form","pptxv-ai-composer"),d=co(t,"textarea","pptxv-ai-input");d.rows=2,d.placeholder=i("pptx.ai.placeholder"),d.setAttribute("aria-label",i("pptx.ai.placeholder"));let y=co(t,"button","pptxv-ai-send");y.type="submit",y.setAttribute("aria-label",i("pptx.ai.send")),y.appendChild(po(t,"send")),C.append(d,y),n.append(a,...m?[m.el]:[],l,g,f,C);try{c=await(o.createChat??Wn)({bridge:o.bridge,config:o.config});}catch{return s.textContent=i("pptx.ai.unavailableTitle"),d.disabled=true,y.disabled=true,m?.destroy(),{destroy:()=>n.replaceChildren()}}let r=c,b=O({doc:t,t:i,deckId:Un(o.bridge),store:o.historyStore,getMessages:()=>r.getSnapshot().messages,setMessages:u=>r.setMessages(u)});a.insertBefore(b.button,x),n.appendChild(b.el);let k=r.subscribe(()=>b.notifyMessagesChanged()),T=new Set,P=u=>{if(!p)return;let A=u.messages.flatMap(Y=>Nn(Y).filter(Z=>Z.kind==="tool")).at(-1);if(!A||A.kind!=="tool"||A.state==="input-streaming"||T.has(A.toolCallId))return;T.add(A.toolCallId);let L=$n(A.toolName,A.input);L&&L.slideIndex!==void 0&&o.goToSlide?.(L.slideIndex),p.flashToolTarget(L);},M=u=>{q(t,l,u.messages,i),s.hidden=u.messages.length>0,u.messages.length===0&&l.appendChild(s),G(t,g,r.proposals.list(),i,{accept:A=>{p?.flashToolTarget(null),r.proposals.apply(A),M(r.getSnapshot());},reject:A=>{r.proposals.revert(A),M(r.getSnapshot());},acceptAll:()=>{p?.flashToolTarget(null),r.proposals.acceptAll(),M(r.getSnapshot());}});let w=u.status==="submitted"||u.status==="streaming";n.classList.toggle("is-busy",w),y.setAttribute("aria-label",i(w?"pptx.ai.stop":"pptx.ai.send")),f.hidden=!u.error,f.textContent=u.error?i("pptx.ai.errorPrefix"):"",l.scrollTop=l.scrollHeight,P(u);},S=()=>{if(n.classList.contains("is-busy")){r.stop();return}let u=d.value.trim();u&&(d.value="",r.sendMessage(u));};C.addEventListener("submit",u=>{u.preventDefault(),S();}),d.addEventListener("keydown",u=>{u.key==="Enter"&&!u.shiftKey&&(u.preventDefault(),S());});let I=p?.getPrefill().nonce??0,J=()=>{if(!p)return;let u=p.getPrefill();u.nonce!==I&&(I=u.nonce,d.value=u.text,d.focus());},Q=p?.subscribe(J),X=r.subscribe(M);return M(r.getSnapshot()),{changeAnimator:r.changeAnimator,destroy(){X(),k(),b.destroy(),Q?.(),m?.destroy(),n.replaceChildren();}}}export{wt as createAiPanel};