pptx-vanilla-viewer 2.12.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
@@ -3347,6 +3430,23 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3347
3430
  .pptxv-anim-bar-seg.is-exit { background: rgb(239 68 68 / 0.6); }
3348
3431
  .pptxv-anim-bar-seg.is-none { background: color-mix(in srgb, var(--pptx-muted-foreground) 40%, transparent); }
3349
3432
  .pptxv-anim-bar-seg.is-selected { outline: 1px solid var(--pptx-ring); }
3433
+ /* Below this width, matches isDensePanelCompact()/MOBILE_BREAKPOINT (768) in
3434
+ pptx-viewer-shared: getDensePanelTouchTargetPx(width) returns
3435
+ MIN_TOUCH_TARGET_PX (44) instead of DEFAULT_DENSE_BUTTON_PX (28), so the
3436
+ direction picker and the Preview button clear a touch-sized hit area. The
3437
+ panel is already single-column at every width. */
3438
+ @media (max-width: 767px) {
3439
+ .pptxv-anim-direction-btn, .pptxv-anim-preview-btn {
3440
+ min-width: 44px !important;
3441
+ min-height: 44px !important;
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
+ }
3449
+ }
3350
3450
 
3351
3451
  /* ── Comments tab: threads, replies, edit-in-place ───────────────────── */
3352
3452
  .pptxv-inspector-comment-badge {
@@ -3423,6 +3523,28 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3423
3523
  }
3424
3524
  .pptxv-action-return-row[hidden] { display: none; }
3425
3525
 
3526
+ /* ── Table style editor: touch target only ────────────────────────────
3527
+ .pptxv-tse and .pptxv-tsef classes (table-style-editor.ts /
3528
+ table-style-editor-fields.ts) otherwise carry no CSS at all in this
3529
+ binding (unstyled/browser-default buttons) - out of scope to redesign
3530
+ here, but the Bold/Italic/Underline toggles and the editor's own action
3531
+ buttons still need to clear the WCAG touch target below the mobile
3532
+ breakpoint (768, MOBILE_BREAKPOINT / MIN_TOUCH_TARGET_PX in
3533
+ pptx-viewer-shared) since they are real, single-letter/narrow buttons. */
3534
+ @media (max-width: 767px) {
3535
+ .pptxv-tsef-toggle, .pptxv-tse-btn, .pptxv-tse-parts button, .pptxv-tse-actions button, .pptxv-tse-header button {
3536
+ min-width: 44px !important;
3537
+ min-height: 44px !important;
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
+ }
3546
+ }
3547
+
3426
3548
 
3427
3549
  /* ── Quick Styles gallery ────────────────────────────────────────────── */
3428
3550
  .pptxv-quick-styles {
@@ -3440,6 +3562,13 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3440
3562
  }
3441
3563
  .pptxv-quick-style:hover:not(:disabled) { outline: 2px solid var(--pptx-primary); outline-offset: -1px; }
3442
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
+ }
3443
3572
 
3444
3573
  /* ── 3D text ─────────────────────────────────────────────────────────── */
3445
3574
  .pptxv-text3d-options { display: grid; gap: 6px; }
@@ -3469,7 +3598,7 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3469
3598
  }
3470
3599
  .pptxv-chart-grid-btn:hover:not(:disabled) { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
3471
3600
  .pptxv-chart-grid-table { width: 100%; border-collapse: collapse; font-size: 11px; }
3472
- .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; }
3473
3602
  .pptxv-chart-grid-table th { font-weight: 400; }
3474
3603
  .pptxv-chart-grid-table :is(th, td) { display: table-cell; white-space: nowrap; }
3475
3604
  .pptxv-chart-grid-cell {
@@ -3497,6 +3626,23 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3497
3626
  cursor: pointer;
3498
3627
  }
3499
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
+ }
3500
3646
 
3501
3647
  /* ── Table data grid ─────────────────────────────────────────────────── */
3502
3648
  .pptxv-table-grid-header { display: flex; align-items: center; justify-content: space-between; gap: 4px; }
@@ -3523,7 +3669,7 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3523
3669
  align-items: center;
3524
3670
  justify-content: center;
3525
3671
  gap: 2px;
3526
- min-width: 0;
3672
+ min-width: 72px;
3527
3673
  margin: -1px 0 0 -1px;
3528
3674
  padding: 1px 3px;
3529
3675
  border: 1px solid var(--pptx-border);
@@ -3531,11 +3677,11 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3531
3677
  color: var(--pptx-muted-foreground);
3532
3678
  white-space: nowrap;
3533
3679
  }
3534
- .pptxv-table-grid-gutter { flex: 0 0 38px; }
3680
+ .pptxv-table-grid-gutter { flex: 0 0 38px; min-width: 38px; }
3535
3681
  .pptxv-table-grid-cell {
3536
3682
  display: flex;
3537
3683
  flex: 1 1 56px;
3538
- min-width: 0;
3684
+ min-width: 72px;
3539
3685
  margin: -1px 0 0 -1px;
3540
3686
  padding: 1px;
3541
3687
  border: 1px solid var(--pptx-border);
@@ -3564,6 +3710,24 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3564
3710
  }
3565
3711
  .pptxv-table-grid-remove[hidden] { display: none; }
3566
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
+ }
3567
3731
 
3568
3732
  /* ── Media trim timeline ─────────────────────────────────────────────── */
3569
3733
  .pptxv-media-timeline { display: grid; gap: 2px; margin: 6px 0; }
@@ -3756,6 +3920,43 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
3756
3920
  }
3757
3921
  .pptxv-image-alt-input:focus-visible { outline: 2px solid var(--pptx-ring); outline-offset: -1px; }
3758
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
+
3759
3960
 
3760
3961
  .pptxv-account { display: flex; flex-direction: column; gap: 28px; max-width: 640px; margin-top: 24px; }
3761
3962
  .pptxv-account-section { padding: 20px; border: 1px solid var(--pptx-border); border-radius: 8px; background: var(--pptx-card); color: var(--pptx-card-foreground); }
@@ -4070,6 +4271,9 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
4070
4271
  box-shadow: 0 -12px 36px rgb(0 0 0 / 0.35);
4071
4272
  }
4072
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; }
4073
4277
  }
4074
4278
 
4075
4279
 
@@ -4201,6 +4405,11 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
4201
4405
  font-size: 0.625rem;
4202
4406
  color: var(--pptx-muted-foreground);
4203
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
+ }
4204
4413
 
4205
4414
 
4206
4415
  /* ── Focused-target bar ───────────────────────────────────────────────── */
@@ -4270,6 +4479,11 @@ svg[data-pptx-motion-path-overlay] [data-pptx-motion-path-handle] { pointer-even
4270
4479
  cursor: pointer;
4271
4480
  }
4272
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
+ }
4273
4487
 
4274
4488
  /* ── Pick-mode banner ─────────────────────────────────────────────────── */
4275
4489
  .pptxv-ai-focus-pick {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-vanilla-viewer",
3
- "version": "2.12.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 chunkWTF4OTWQ_cjs=require('./chunk-WTF4OTWQ.cjs');require('./chunk-B5PFHICE.cjs');function K(o){let{doc:t,t:n,controller:i}=o,a=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-focus"),h=(p,m,l)=>{let s=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-focus-btn");return s.type="button",s.title=m,s.setAttribute("aria-label",m),s.appendChild(chunkWTF4OTWQ_cjs.io(t,p)),s.addEventListener("click",l),s},x=()=>{a.replaceChildren();let p=i.getEffectiveTargets(),m=i.hasPicks(),l=i.isPinned(),s=i.isPicking(),g=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-focus-row"),f=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-focus-label");f.textContent=n("pptx.ai.focusScope"),g.appendChild(f);for(let r of chunkWTF4OTWQ_cjs.Kn(p,o.getSlides())){let b=chunkWTF4OTWQ_cjs.Xn(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=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-focus-pinned");r.textContent=n("pptx.ai.pinnedFocus"),g.appendChild(r);}let C=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-focus-actions"),d=chunkWTF4OTWQ_cjs.Ln(p,o.getSlides());if(d){let r=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-focus-merge");r.type="button",r.append(chunkWTF4OTWQ_cjs.io(t,"git-merge"),t.createTextNode(n("pptx.ai.mergeSelectedTables"))),r.addEventListener("click",()=>o.onSendDirective(chunkWTF4OTWQ_cjs.Mn(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=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-focus-pick"),b=chunkWTF4OTWQ_cjs.io(t,"crosshair");b.classList.add("pptxv-ai-focus-pick-icon");let k=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-focus-pick-hint");k.textContent=n("pptx.ai.pickElementHint");let T=chunkWTF4OTWQ_cjs.Xn(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=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-chats");i.type="button",i.append(chunkWTF4OTWQ_cjs.io(t,"history"),t.createTextNode(n("pptx.ai.chats")));let a=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-history");a.hidden=true;let h=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-history-head"),x=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-history-title");x.textContent=n("pptx.ai.historyTitle");let c=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-history-new");c.type="button",c.append(chunkWTF4OTWQ_cjs.io(t,"plus"),t.createTextNode(n("pptx.ai.newChat"))),h.append(x,c);let p=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-history-body"),m=chunkWTF4OTWQ_cjs.Xn(t,"p","pptxv-ai-history-hint");m.textContent=n("pptx.ai.historyHint"),a.append(h,p,m);let l=chunkWTF4OTWQ_cjs.On({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=chunkWTF4OTWQ_cjs.Xn(t,"p","pptxv-ai-history-empty");d.textContent=n("pptx.ai.historyEmpty"),p.appendChild(d);return}let C=chunkWTF4OTWQ_cjs.Xn(t,"ul","pptxv-ai-history-list");for(let d of f){let y=chunkWTF4OTWQ_cjs.Xn(t,"li","pptxv-ai-history-row"),r=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-history-resume");r.type="button",r.classList.toggle("is-active",d.id===l.activeChatId());let b=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-history-text"),k=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-history-name");k.textContent=d.title||n("pptx.ai.untitledChat");let T=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-history-meta");T.textContent=n("pptx.ai.messageCount",{count:d.messageCount}),b.append(k,T),r.append(chunkWTF4OTWQ_cjs.io(t,"comment"),b),r.addEventListener("click",()=>{l.resumeChat(d.id),a.hidden=true;});let P=chunkWTF4OTWQ_cjs.Xn(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(chunkWTF4OTWQ_cjs.io(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=chunkWTF4OTWQ_cjs.Tn(t.toolName,t.input,h?"present":"past"),c=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-tool"),p=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-tool-head"),m=chunkWTF4OTWQ_cjs.io(o,_[x.icon]??"wrench");m.classList.add("pptxv-ai-tool-icon");let l=chunkWTF4OTWQ_cjs.Xn(o,"span","pptxv-ai-tool-name");l.textContent=x.label;let s=chunkWTF4OTWQ_cjs.Xn(o,"span","pptxv-ai-tool-state");if(i?(s.classList.add("is-error"),s.append(chunkWTF4OTWQ_cjs.io(o,"alert"),o.createTextNode(n("pptx.ai.toolFailed")))):a?(s.classList.add("is-done"),s.append(chunkWTF4OTWQ_cjs.io(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=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-tool-error");f.textContent=t.errorText,c.appendChild(f);}let g=chunkWTF4OTWQ_cjs.Sn(t.input);if(g){let f=chunkWTF4OTWQ_cjs.Xn(o,"details","pptxv-ai-tool-details"),C=chunkWTF4OTWQ_cjs.Xn(o,"summary");C.textContent=n("pptx.ai.toolDetails");let d=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-tool-raw");d.textContent=`${chunkWTF4OTWQ_cjs.Rn(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=chunkWTF4OTWQ_cjs.Gn(a);if(x.length===0&&!h)continue;let c=chunkWTF4OTWQ_cjs.Xn(o,"div",`pptxv-ai-msg pptxv-ai-msg-${a.role}`),p=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-msg-avatar");p.setAttribute("aria-label",i(h?"pptx.ai.you":"pptx.ai.assistant")),p.appendChild(chunkWTF4OTWQ_cjs.io(o,h?"comment":"sparkles"));let m=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-msg-body");for(let l of x)if(l.kind==="text"){let s=chunkWTF4OTWQ_cjs.Xn(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=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-proposals-header"),x=chunkWTF4OTWQ_cjs.Xn(o,"span","pptxv-ai-proposals-title");if(x.textContent=i("pptx.ai.pendingChanges",{count:n.length}),h.appendChild(x),n.length>1){let c=chunkWTF4OTWQ_cjs.Xn(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=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-proposal");a.dataset.proposalId=t.id;let h=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-proposal-eyebrow");h.textContent=n("pptx.ai.proposedChange"),a.appendChild(h);let x=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-proposal-label");if(x.textContent=t.label,a.appendChild(x),t.summary.length>0){let l=chunkWTF4OTWQ_cjs.Xn(o,"ul","pptxv-ai-proposal-summary");for(let s of t.summary){let g=chunkWTF4OTWQ_cjs.Xn(o,"li");g.textContent=chunkWTF4OTWQ_cjs.Dn(s),l.appendChild(g);}a.appendChild(l);}let c=chunkWTF4OTWQ_cjs.Xn(o,"div","pptxv-ai-proposal-actions"),p=chunkWTF4OTWQ_cjs.Xn(o,"button","pptxv-ai-proposal-btn is-accept");p.type="button",p.append(chunkWTF4OTWQ_cjs.io(o,"check"),o.createTextNode(n("pptx.ai.accept"))),p.addEventListener("click",()=>i.accept(t.id));let m=chunkWTF4OTWQ_cjs.Xn(o,"button","pptxv-ai-proposal-btn is-reject");return m.type="button",m.append(chunkWTF4OTWQ_cjs.io(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=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-header"),h=chunkWTF4OTWQ_cjs.Xn(t,"span","pptxv-ai-title");h.textContent=i("pptx.ai.title");let x=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-close");x.type="button",x.title=i("pptx.ai.close"),x.setAttribute("aria-label",i("pptx.ai.close")),x.appendChild(chunkWTF4OTWQ_cjs.io(t,"close")),x.addEventListener("click",()=>o.onClose?.()),a.append(chunkWTF4OTWQ_cjs.io(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=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-messages");l.setAttribute("role","log"),l.setAttribute("aria-live","polite");let s=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-empty");s.textContent=i("pptx.ai.emptyHint"),l.appendChild(s);let g=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-proposals");g.hidden=true;let f=chunkWTF4OTWQ_cjs.Xn(t,"div","pptxv-ai-error");f.setAttribute("role","alert"),f.hidden=true;let C=chunkWTF4OTWQ_cjs.Xn(t,"form","pptxv-ai-composer"),d=chunkWTF4OTWQ_cjs.Xn(t,"textarea","pptxv-ai-input");d.rows=2,d.placeholder=i("pptx.ai.placeholder"),d.setAttribute("aria-label",i("pptx.ai.placeholder"));let y=chunkWTF4OTWQ_cjs.Xn(t,"button","pptxv-ai-send");y.type="submit",y.setAttribute("aria-label",i("pptx.ai.send")),y.appendChild(chunkWTF4OTWQ_cjs.io(t,"send")),C.append(d,y),n.append(a,...m?[m.el]:[],l,g,f,C);try{c=await(o.createChat??chunkWTF4OTWQ_cjs.Pn)({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:chunkWTF4OTWQ_cjs.Nn(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=>chunkWTF4OTWQ_cjs.Gn(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=chunkWTF4OTWQ_cjs.Un(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 {Xn,io,Pn,Nn,On,Gn,Un,Kn,Ln,Mn,Tn,Sn,Rn,Dn}from'./chunk-56CORRDB.js';import'./chunk-62D2TNHX.js';function K(o){let{doc:t,t:n,controller:i}=o,a=Xn(t,"div","pptxv-ai-focus"),h=(p,m,l)=>{let s=Xn(t,"button","pptxv-ai-focus-btn");return s.type="button",s.title=m,s.setAttribute("aria-label",m),s.appendChild(io(t,p)),s.addEventListener("click",l),s},x=()=>{a.replaceChildren();let p=i.getEffectiveTargets(),m=i.hasPicks(),l=i.isPinned(),s=i.isPicking(),g=Xn(t,"div","pptxv-ai-focus-row"),f=Xn(t,"span","pptxv-ai-focus-label");f.textContent=n("pptx.ai.focusScope"),g.appendChild(f);for(let r of Kn(p,o.getSlides())){let b=Xn(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=Xn(t,"span","pptxv-ai-focus-pinned");r.textContent=n("pptx.ai.pinnedFocus"),g.appendChild(r);}let C=Xn(t,"div","pptxv-ai-focus-actions"),d=Ln(p,o.getSlides());if(d){let r=Xn(t,"button","pptxv-ai-focus-merge");r.type="button",r.append(io(t,"git-merge"),t.createTextNode(n("pptx.ai.mergeSelectedTables"))),r.addEventListener("click",()=>o.onSendDirective(Mn(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=Xn(t,"div","pptxv-ai-focus-pick"),b=io(t,"crosshair");b.classList.add("pptxv-ai-focus-pick-icon");let k=Xn(t,"span","pptxv-ai-focus-pick-hint");k.textContent=n("pptx.ai.pickElementHint");let T=Xn(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=Xn(t,"button","pptxv-ai-chats");i.type="button",i.append(io(t,"history"),t.createTextNode(n("pptx.ai.chats")));let a=Xn(t,"div","pptxv-ai-history");a.hidden=true;let h=Xn(t,"div","pptxv-ai-history-head"),x=Xn(t,"span","pptxv-ai-history-title");x.textContent=n("pptx.ai.historyTitle");let c=Xn(t,"button","pptxv-ai-history-new");c.type="button",c.append(io(t,"plus"),t.createTextNode(n("pptx.ai.newChat"))),h.append(x,c);let p=Xn(t,"div","pptxv-ai-history-body"),m=Xn(t,"p","pptxv-ai-history-hint");m.textContent=n("pptx.ai.historyHint"),a.append(h,p,m);let l=On({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=Xn(t,"p","pptxv-ai-history-empty");d.textContent=n("pptx.ai.historyEmpty"),p.appendChild(d);return}let C=Xn(t,"ul","pptxv-ai-history-list");for(let d of f){let y=Xn(t,"li","pptxv-ai-history-row"),r=Xn(t,"button","pptxv-ai-history-resume");r.type="button",r.classList.toggle("is-active",d.id===l.activeChatId());let b=Xn(t,"span","pptxv-ai-history-text"),k=Xn(t,"span","pptxv-ai-history-name");k.textContent=d.title||n("pptx.ai.untitledChat");let T=Xn(t,"span","pptxv-ai-history-meta");T.textContent=n("pptx.ai.messageCount",{count:d.messageCount}),b.append(k,T),r.append(io(t,"comment"),b),r.addEventListener("click",()=>{l.resumeChat(d.id),a.hidden=true;});let P=Xn(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(io(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=Tn(t.toolName,t.input,h?"present":"past"),c=Xn(o,"div","pptxv-ai-tool"),p=Xn(o,"div","pptxv-ai-tool-head"),m=io(o,_[x.icon]??"wrench");m.classList.add("pptxv-ai-tool-icon");let l=Xn(o,"span","pptxv-ai-tool-name");l.textContent=x.label;let s=Xn(o,"span","pptxv-ai-tool-state");if(i?(s.classList.add("is-error"),s.append(io(o,"alert"),o.createTextNode(n("pptx.ai.toolFailed")))):a?(s.classList.add("is-done"),s.append(io(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=Xn(o,"div","pptxv-ai-tool-error");f.textContent=t.errorText,c.appendChild(f);}let g=Sn(t.input);if(g){let f=Xn(o,"details","pptxv-ai-tool-details"),C=Xn(o,"summary");C.textContent=n("pptx.ai.toolDetails");let d=Xn(o,"div","pptxv-ai-tool-raw");d.textContent=`${Rn(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=Gn(a);if(x.length===0&&!h)continue;let c=Xn(o,"div",`pptxv-ai-msg pptxv-ai-msg-${a.role}`),p=Xn(o,"div","pptxv-ai-msg-avatar");p.setAttribute("aria-label",i(h?"pptx.ai.you":"pptx.ai.assistant")),p.appendChild(io(o,h?"comment":"sparkles"));let m=Xn(o,"div","pptxv-ai-msg-body");for(let l of x)if(l.kind==="text"){let s=Xn(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=Xn(o,"div","pptxv-ai-proposals-header"),x=Xn(o,"span","pptxv-ai-proposals-title");if(x.textContent=i("pptx.ai.pendingChanges",{count:n.length}),h.appendChild(x),n.length>1){let c=Xn(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=Xn(o,"div","pptxv-ai-proposal");a.dataset.proposalId=t.id;let h=Xn(o,"div","pptxv-ai-proposal-eyebrow");h.textContent=n("pptx.ai.proposedChange"),a.appendChild(h);let x=Xn(o,"div","pptxv-ai-proposal-label");if(x.textContent=t.label,a.appendChild(x),t.summary.length>0){let l=Xn(o,"ul","pptxv-ai-proposal-summary");for(let s of t.summary){let g=Xn(o,"li");g.textContent=Dn(s),l.appendChild(g);}a.appendChild(l);}let c=Xn(o,"div","pptxv-ai-proposal-actions"),p=Xn(o,"button","pptxv-ai-proposal-btn is-accept");p.type="button",p.append(io(o,"check"),o.createTextNode(n("pptx.ai.accept"))),p.addEventListener("click",()=>i.accept(t.id));let m=Xn(o,"button","pptxv-ai-proposal-btn is-reject");return m.type="button",m.append(io(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=Xn(t,"div","pptxv-ai-header"),h=Xn(t,"span","pptxv-ai-title");h.textContent=i("pptx.ai.title");let x=Xn(t,"button","pptxv-ai-close");x.type="button",x.title=i("pptx.ai.close"),x.setAttribute("aria-label",i("pptx.ai.close")),x.appendChild(io(t,"close")),x.addEventListener("click",()=>o.onClose?.()),a.append(io(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=Xn(t,"div","pptxv-ai-messages");l.setAttribute("role","log"),l.setAttribute("aria-live","polite");let s=Xn(t,"div","pptxv-ai-empty");s.textContent=i("pptx.ai.emptyHint"),l.appendChild(s);let g=Xn(t,"div","pptxv-ai-proposals");g.hidden=true;let f=Xn(t,"div","pptxv-ai-error");f.setAttribute("role","alert"),f.hidden=true;let C=Xn(t,"form","pptxv-ai-composer"),d=Xn(t,"textarea","pptxv-ai-input");d.rows=2,d.placeholder=i("pptx.ai.placeholder"),d.setAttribute("aria-label",i("pptx.ai.placeholder"));let y=Xn(t,"button","pptxv-ai-send");y.type="submit",y.setAttribute("aria-label",i("pptx.ai.send")),y.appendChild(io(t,"send")),C.append(d,y),n.append(a,...m?[m.el]:[],l,g,f,C);try{c=await(o.createChat??Pn)({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:Nn(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=>Gn(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=Un(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};