@embedpdf/viewer-chrome 3.0.0-next.15 → 3.0.0-next.16
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/{annotation-fonts-BqoLZ4Mp.js → annotation-fonts-DWjVOTP0.js} +2 -2
- package/dist/{annotation-fonts-BqoLZ4Mp.js.map → annotation-fonts-DWjVOTP0.js.map} +1 -1
- package/dist/{annotation-fonts-Dt0IQXhz.cjs → annotation-fonts-dpfVkhnq.cjs} +2 -2
- package/dist/{annotation-fonts-Dt0IQXhz.cjs.map → annotation-fonts-dpfVkhnq.cjs.map} +1 -1
- package/dist/{annotation-style-Bzvvp8-N.cjs → annotation-style-B3XKAyZ-.cjs} +3 -3
- package/dist/{annotation-style-Bzvvp8-N.cjs.map → annotation-style-B3XKAyZ-.cjs.map} +1 -1
- package/dist/{annotation-style--rPIZsuP.js → annotation-style-CXF3X47Z.js} +3 -3
- package/dist/{annotation-style--rPIZsuP.js.map → annotation-style-CXF3X47Z.js.map} +1 -1
- package/dist/{ar-DnEj5vbP.cjs → ar-B132r9bo.cjs} +93 -1
- package/dist/ar-B132r9bo.cjs.map +1 -0
- package/dist/{ar-D9XKAmDx.js → ar-BLWFJoA_.js} +93 -1
- package/dist/ar-BLWFJoA_.js.map +1 -0
- package/dist/attachments-panel-Cxln8xos.cjs +217 -0
- package/dist/attachments-panel-Cxln8xos.cjs.map +1 -0
- package/dist/attachments-panel-H1ucRbwo.js +217 -0
- package/dist/attachments-panel-H1ucRbwo.js.map +1 -0
- package/dist/chrome.cjs +21 -0
- package/dist/chrome.cjs.map +1 -1
- package/dist/chrome.js +21 -0
- package/dist/chrome.js.map +1 -1
- package/dist/{commands-BmgxhJ8B.js → commands-BkgLP3Om.js} +418 -23
- package/dist/commands-BkgLP3Om.js.map +1 -0
- package/dist/{commands-CYt4SFUX.cjs → commands-DL1gjZt7.cjs} +433 -20
- package/dist/commands-DL1gjZt7.cjs.map +1 -0
- package/dist/commands.cjs +2 -1
- package/dist/commands.d.cts +3 -1
- package/dist/commands.d.ts +3 -1
- package/dist/commands.js +2 -2
- package/dist/{comments-panel-pEcQg4Vs.cjs → comments-panel-BsnWedTh.cjs} +2 -2
- package/dist/{comments-panel-pEcQg4Vs.cjs.map → comments-panel-BsnWedTh.cjs.map} +1 -1
- package/dist/{comments-panel-MUVgLCBI.js → comments-panel-D7Eadws9.js} +2 -2
- package/dist/{comments-panel-MUVgLCBI.js.map → comments-panel-D7Eadws9.js.map} +1 -1
- package/dist/{de-Dv6zvbnd.cjs → de-7_MvFWzN.cjs} +93 -1
- package/dist/de-7_MvFWzN.cjs.map +1 -0
- package/dist/{de-Bdr4aWzm.js → de-BUhwc9-x.js} +93 -1
- package/dist/de-BUhwc9-x.js.map +1 -0
- package/dist/{dialog-B5GBisKv.js → dialog-BIb373cg.js} +3 -3
- package/dist/dialog-BIb373cg.js.map +1 -0
- package/dist/{dialog-t8F13BL_.cjs → dialog-CngKTnAM.cjs} +3 -3
- package/dist/dialog-CngKTnAM.cjs.map +1 -0
- package/dist/{es-BP09DR9w.cjs → es-DgYj-1L3.cjs} +93 -1
- package/dist/es-DgYj-1L3.cjs.map +1 -0
- package/dist/{es-BSXz5tBv.js → es-DoXTqFoO.js} +93 -1
- package/dist/es-DoXTqFoO.js.map +1 -0
- package/dist/{form-design-panel-vWWU9uB-.js → form-design-panel-CgV_5YWC.js} +3 -3
- package/dist/{form-design-panel-vWWU9uB-.js.map → form-design-panel-CgV_5YWC.js.map} +1 -1
- package/dist/{form-design-panel-B5MXTZ96.cjs → form-design-panel-D0FdmWXW.cjs} +3 -3
- package/dist/{form-design-panel-B5MXTZ96.cjs.map → form-design-panel-D0FdmWXW.cjs.map} +1 -1
- package/dist/{fr-Ckn3K9v1.js → fr-B-8NDhBA.js} +93 -1
- package/dist/fr-B-8NDhBA.js.map +1 -0
- package/dist/{fr-BBQQn7tJ.cjs → fr-C856dmQJ.cjs} +93 -1
- package/dist/fr-C856dmQJ.cjs.map +1 -0
- package/dist/{he-DRsG7bH7.cjs → he-BFTeNc4t.cjs} +93 -1
- package/dist/he-BFTeNc4t.cjs.map +1 -0
- package/dist/{he-wdGU5PkU.js → he-Dlh0fNXM.js} +93 -1
- package/dist/he-Dlh0fNXM.js.map +1 -0
- package/dist/{icons-x0Tc05bs.cjs → icons-1UfLUZ_y.cjs} +20 -1
- package/dist/icons-1UfLUZ_y.cjs.map +1 -0
- package/dist/{icons-BrK5iVL8.js → icons-7dB0Y1ct.js} +20 -1
- package/dist/icons-7dB0Y1ct.js.map +1 -0
- package/dist/index.cjs +740 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +727 -170
- package/dist/index.js.map +1 -1
- package/dist/{it-BuP4o0xQ.cjs → it-Bef-2Yxq.cjs} +93 -1
- package/dist/it-Bef-2Yxq.cjs.map +1 -0
- package/dist/{it-Us-VmvIu.js → it-BkirG7ol.js} +93 -1
- package/dist/it-BkirG7ol.js.map +1 -0
- package/dist/{ja-Cizj0-5O.js → ja-CGEjCE-s.js} +93 -1
- package/dist/ja-CGEjCE-s.js.map +1 -0
- package/dist/{ja-DovEd6ts.cjs → ja-DNw2zqSD.cjs} +93 -1
- package/dist/ja-DNw2zqSD.cjs.map +1 -0
- package/dist/{ko-DlrXliE1.js → ko-CTkl5vMh.js} +93 -1
- package/dist/ko-CTkl5vMh.js.map +1 -0
- package/dist/{ko-B-qJEol2.cjs → ko-YHzeBqP6.cjs} +93 -1
- package/dist/ko-YHzeBqP6.cjs.map +1 -0
- package/dist/{link-editor-CSjqPnj1.cjs → link-editor-CAS7MZM2.cjs} +2 -2
- package/dist/{link-editor-CSjqPnj1.cjs.map → link-editor-CAS7MZM2.cjs.map} +1 -1
- package/dist/{link-editor-SxM1nnJU.js → link-editor-CkwtqRvb.js} +2 -2
- package/dist/{link-editor-SxM1nnJU.js.map → link-editor-CkwtqRvb.js.map} +1 -1
- package/dist/{measurement-Bs61XWbJ.js → measurement-CQdbnIrn.js} +2 -2
- package/dist/{measurement-Bs61XWbJ.js.map → measurement-CQdbnIrn.js.map} +1 -1
- package/dist/{measurement-CcCsHPOX.cjs → measurement-Cxv1Ahxx.cjs} +2 -2
- package/dist/{measurement-CcCsHPOX.cjs.map → measurement-Cxv1Ahxx.cjs.map} +1 -1
- package/dist/{nl-D3KZDDiJ.cjs → nl-BjkbaLq3.cjs} +93 -1
- package/dist/nl-BjkbaLq3.cjs.map +1 -0
- package/dist/{nl-0aF7M_0h.js → nl-Dya4sR8_.js} +93 -1
- package/dist/nl-Dya4sR8_.js.map +1 -0
- package/dist/outline-panel-BpGtBdj0.cjs +707 -0
- package/dist/outline-panel-BpGtBdj0.cjs.map +1 -0
- package/dist/outline-panel-DO5_REYw.js +707 -0
- package/dist/outline-panel-DO5_REYw.js.map +1 -0
- package/dist/outline-properties-BCa2cc0t.js +330 -0
- package/dist/outline-properties-BCa2cc0t.js.map +1 -0
- package/dist/outline-properties-DT3FIxCw.cjs +330 -0
- package/dist/outline-properties-DT3FIxCw.cjs.map +1 -0
- package/dist/{pl-DSFhAUqx.cjs → pl-CKKdVnpZ.cjs} +93 -1
- package/dist/pl-CKKdVnpZ.cjs.map +1 -0
- package/dist/{pl-BW--AaCI.js → pl-DA9b5NVg.js} +93 -1
- package/dist/pl-DA9b5NVg.js.map +1 -0
- package/dist/print-dialog-BqIrHCBh.cjs +276 -0
- package/dist/print-dialog-BqIrHCBh.cjs.map +1 -0
- package/dist/print-dialog-DvcI2m2_.js +276 -0
- package/dist/print-dialog-DvcI2m2_.js.map +1 -0
- package/dist/{pt-C5S-8MC5.cjs → pt-DLcszlzi.cjs} +93 -1
- package/dist/pt-DLcszlzi.cjs.map +1 -0
- package/dist/{pt-DIhpU5pT.js → pt-Nm8yyjbX.js} +93 -1
- package/dist/pt-Nm8yyjbX.js.map +1 -0
- package/dist/{redact-confirm-CX_SY2ZN.cjs → redact-confirm-C6EiK8yN.cjs} +2 -2
- package/dist/{redact-confirm-CX_SY2ZN.cjs.map → redact-confirm-C6EiK8yN.cjs.map} +1 -1
- package/dist/{redact-confirm-B6j36TPw.js → redact-confirm-CKuv9iN_.js} +2 -2
- package/dist/{redact-confirm-B6j36TPw.js.map → redact-confirm-CKuv9iN_.js.map} +1 -1
- package/dist/{redaction-panel-IJDshSJI.js → redaction-panel-CgNZ-pQk.js} +2 -2
- package/dist/{redaction-panel-IJDshSJI.js.map → redaction-panel-CgNZ-pQk.js.map} +1 -1
- package/dist/{redaction-panel-BmoIl-Ll.cjs → redaction-panel-ZhX0dlMi.cjs} +2 -2
- package/dist/{redaction-panel-BmoIl-Ll.cjs.map → redaction-panel-ZhX0dlMi.cjs.map} +1 -1
- package/dist/{search-panel-HfIhJm1M.js → search-panel-BE4xzWlm.js} +4 -4
- package/dist/{search-panel-HfIhJm1M.js.map → search-panel-BE4xzWlm.js.map} +1 -1
- package/dist/{search-panel-s9IoiOtv.cjs → search-panel-wcbTNG1z.cjs} +4 -4
- package/dist/{search-panel-s9IoiOtv.cjs.map → search-panel-wcbTNG1z.cjs.map} +1 -1
- package/dist/{sheet-BDsa_Sup.cjs → sheet-DTBFiwde.cjs} +30 -11
- package/dist/sheet-DTBFiwde.cjs.map +1 -0
- package/dist/{sheet-R6XDgyEf.js → sheet-DyjKfAq0.js} +25 -12
- package/dist/sheet-DyjKfAq0.js.map +1 -0
- package/dist/{sign-dialog-CgnR7akj.cjs → sign-dialog-D5WGx-Yn.cjs} +2 -2
- package/dist/{sign-dialog-CgnR7akj.cjs.map → sign-dialog-D5WGx-Yn.cjs.map} +1 -1
- package/dist/{sign-dialog-GDqCoQhA.js → sign-dialog-DerNe8qT.js} +2 -2
- package/dist/{sign-dialog-GDqCoQhA.js.map → sign-dialog-DerNe8qT.js.map} +1 -1
- package/dist/{signature-inspector-DyO313Qf.cjs → signature-inspector-Bz6TAfZM.cjs} +4 -10
- package/dist/signature-inspector-Bz6TAfZM.cjs.map +1 -0
- package/dist/{signature-inspector-okFz8do6.js → signature-inspector-CsGr9EBk.js} +4 -10
- package/dist/signature-inspector-CsGr9EBk.js.map +1 -0
- package/dist/{signature-maker-BoYa8vgA.cjs → signature-maker-D_YfBXLn.cjs} +3 -3
- package/dist/{signature-maker-BoYa8vgA.cjs.map → signature-maker-D_YfBXLn.cjs.map} +1 -1
- package/dist/{signature-maker-BhCmYyHD.js → signature-maker-Dnth4rV4.js} +3 -3
- package/dist/{signature-maker-BhCmYyHD.js.map → signature-maker-Dnth4rV4.js.map} +1 -1
- package/dist/{signatures-panel-B56PC6d9.cjs → signatures-panel-Ci_LaI1C.cjs} +4 -10
- package/dist/signatures-panel-Ci_LaI1C.cjs.map +1 -0
- package/dist/{signatures-panel-CgnFfhFm.js → signatures-panel-DZ9ywrjz.js} +4 -10
- package/dist/signatures-panel-DZ9ywrjz.js.map +1 -0
- package/dist/{stamps-panel-CDO0FPyK.js → stamps-panel-BrczStaz.js} +4 -10
- package/dist/stamps-panel-BrczStaz.js.map +1 -0
- package/dist/{stamps-panel-B9NYGayn.cjs → stamps-panel-Cv9nJBwx.cjs} +4 -10
- package/dist/stamps-panel-Cv9nJBwx.cjs.map +1 -0
- package/dist/theme-Be0OZokZ.js +97 -0
- package/dist/theme-Be0OZokZ.js.map +1 -0
- package/dist/theme-FR26JI3r.cjs +126 -0
- package/dist/theme-FR26JI3r.cjs.map +1 -0
- package/dist/{toolbar-z9od3tKl.js → toolbar-DF361xWY.js} +7 -6
- package/dist/toolbar-DF361xWY.js.map +1 -0
- package/dist/{toolbar-CJu2wKTU.cjs → toolbar-ddvpsvTb.cjs} +7 -6
- package/dist/toolbar-ddvpsvTb.cjs.map +1 -0
- package/dist/{zh-cn-CxkUUBct.js → zh-cn-BMPPkLpL.js} +93 -1
- package/dist/zh-cn-BMPPkLpL.js.map +1 -0
- package/dist/{zh-cn-3tmMeHqv.cjs → zh-cn-CZOO3p4H.cjs} +93 -1
- package/dist/zh-cn-CZOO3p4H.cjs.map +1 -0
- package/package.json +4 -4
- package/src/styles.css +8 -0
- package/dist/ar-D9XKAmDx.js.map +0 -1
- package/dist/ar-DnEj5vbP.cjs.map +0 -1
- package/dist/commands-BmgxhJ8B.js.map +0 -1
- package/dist/commands-CYt4SFUX.cjs.map +0 -1
- package/dist/de-Bdr4aWzm.js.map +0 -1
- package/dist/de-Dv6zvbnd.cjs.map +0 -1
- package/dist/dialog-B5GBisKv.js.map +0 -1
- package/dist/dialog-t8F13BL_.cjs.map +0 -1
- package/dist/es-BP09DR9w.cjs.map +0 -1
- package/dist/es-BSXz5tBv.js.map +0 -1
- package/dist/fr-BBQQn7tJ.cjs.map +0 -1
- package/dist/fr-Ckn3K9v1.js.map +0 -1
- package/dist/he-DRsG7bH7.cjs.map +0 -1
- package/dist/he-wdGU5PkU.js.map +0 -1
- package/dist/icons-BrK5iVL8.js.map +0 -1
- package/dist/icons-x0Tc05bs.cjs.map +0 -1
- package/dist/it-BuP4o0xQ.cjs.map +0 -1
- package/dist/it-Us-VmvIu.js.map +0 -1
- package/dist/ja-Cizj0-5O.js.map +0 -1
- package/dist/ja-DovEd6ts.cjs.map +0 -1
- package/dist/ko-B-qJEol2.cjs.map +0 -1
- package/dist/ko-DlrXliE1.js.map +0 -1
- package/dist/nl-0aF7M_0h.js.map +0 -1
- package/dist/nl-D3KZDDiJ.cjs.map +0 -1
- package/dist/pl-BW--AaCI.js.map +0 -1
- package/dist/pl-DSFhAUqx.cjs.map +0 -1
- package/dist/pt-C5S-8MC5.cjs.map +0 -1
- package/dist/pt-DIhpU5pT.js.map +0 -1
- package/dist/sheet-BDsa_Sup.cjs.map +0 -1
- package/dist/sheet-R6XDgyEf.js.map +0 -1
- package/dist/signature-inspector-DyO313Qf.cjs.map +0 -1
- package/dist/signature-inspector-okFz8do6.js.map +0 -1
- package/dist/signatures-panel-B56PC6d9.cjs.map +0 -1
- package/dist/signatures-panel-CgnFfhFm.js.map +0 -1
- package/dist/stamps-panel-B9NYGayn.cjs.map +0 -1
- package/dist/stamps-panel-CDO0FPyK.js.map +0 -1
- package/dist/toolbar-CJu2wKTU.cjs.map +0 -1
- package/dist/toolbar-z9od3tKl.js.map +0 -1
- package/dist/zh-cn-3tmMeHqv.cjs.map +0 -1
- package/dist/zh-cn-CxkUUBct.js.map +0 -1
package/dist/pt-DIhpU5pT.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pt-DIhpU5pT.js","names":[],"sources":["../src/locales/pt.ts"],"sourcesContent":["import type { Locale } from '@embedpdf/react/i18n';\n\n/**\n * Brazilian Portuguese pack, in the words Adobe Acrobat's Português (Brasil) edition uses.\n * Machine-translated from the English pack (`./en.ts`) and not yet reviewed by a native speaker.\n */\nexport const pt: Locale = {\n code: 'pt',\n name: 'Português',\n translations: {\n measurement: {\n title: 'Medições',\n distance: 'Distância',\n perimeter: 'Perímetro',\n area: 'Área',\n areaUnit: 'Unidade de área',\n resetLabel: 'Redefinir posição do rótulo',\n calibrate: 'Calibrar escala',\n scale: 'Escala',\n custom: 'Personalizada',\n unavailable: 'Indisponível',\n instructions:\n 'Arraste para medir uma distância e clique para posicionar a linha de cota. Clique nos vértices de um perímetro ou área e clique duas vezes para concluir. Os limites da área não podem se cruzar; uma visualização indisponível não pode ser concluída. Pressione Escape para cancelar. Arraste o próprio rótulo para movê-lo.',\n sessionOnly: 'Este mecanismo mantém a calibração da página somente nesta sessão.',\n allPages: 'Aplicar a todas as páginas',\n recalculate: 'Recalcular medições existentes',\n preset: 'Escala predefinida',\n choosePreset: 'Escolha uma predefinição',\n unit: 'Unidade',\n precision: 'Precisão',\n selection: 'Medições selecionadas',\n report: '{updated} atualizadas · {skipped} ignoradas · {failed} com falha',\n knownLength: 'Digite o comprimento real representado pela linha que você acabou de desenhar.',\n length: 'Comprimento conhecido',\n apply: 'Aplicar escala',\n applying: 'Aplicando…',\n },\n commands: {\n zoom: {\n in: 'Ampliar',\n out: 'Reduzir',\n fitPage: 'Ajustar à página',\n fitWidth: 'Ajustar à largura',\n automatic: 'Automático',\n menu: 'Zoom',\n level: 'Nível de zoom',\n p50: '50%',\n p100: '100%',\n p150: '150%',\n p200: '200%',\n p400: '400%',\n },\n pan: 'Deslocar',\n pointer: 'Selecionar',\n comment: 'Comentário',\n style: 'Estilo',\n menu: 'Menu',\n viewControls: 'Controles de exibição',\n open: 'Abrir',\n download: 'Baixar',\n print: 'Imprimir',\n fullscreen: 'Tela cheia',\n spread: {\n group: 'Exibição de página',\n none: 'Página única',\n odd: 'Duas páginas',\n even: 'Página de capa',\n },\n scroll: {\n group: 'Rolagem',\n vertical: 'Vertical',\n horizontal: 'Horizontal',\n },\n rotate: {\n group: 'Girar',\n clockwise: 'Girar no sentido horário',\n counterclockwise: 'Girar no sentido anti-horário',\n },\n mode: {\n measure: 'Medir',\n group: 'Modo',\n view: 'Exibir',\n annotate: 'Anotar',\n shapes: 'Formas',\n insert: 'Inserir',\n form: 'Formulário',\n redact: 'Tarjar',\n },\n annotate: {\n cancelCreation: 'Cancelar desenho',\n highlight: 'Realçar',\n strikeout: 'Tachar',\n underline: 'Sublinhar',\n squiggly: 'Ondulado',\n ink: 'Desenhar',\n inkHighlight: 'Marca-texto',\n text: 'Texto',\n insertText: 'Inserir texto',\n replaceText: 'Substituir texto',\n callout: 'Texto explicativo',\n note: 'Comentário',\n link: 'Link',\n gotoLink: 'Ir para o link',\n removeLink: 'Remover link',\n delete: 'Excluir',\n group: 'Agrupar',\n ungroup: 'Desagrupar',\n stampFromSelection: 'Criar carimbo',\n strip: 'Ações de anotação',\n },\n selection: {\n copy: 'Copiar',\n strip: 'Ações de seleção de texto',\n },\n shapes: {\n rectangle: 'Retângulo',\n circle: 'Círculo',\n line: 'Linha',\n arrow: 'Seta',\n polygon: 'Polígono',\n polyline: 'Polilinha',\n },\n insert: {\n stamp: 'Carimbo',\n attachment: 'Anexar arquivo',\n signature: 'Assinatura',\n image: 'Imagem',\n },\n form: {\n textfield: 'Campo de texto',\n checkbox: 'Caixa de seleção',\n radio: 'Botão de opção',\n select: 'Lista suspensa',\n listbox: 'Caixa de listagem',\n button: 'Botão',\n signature: 'Campo de assinatura',\n // The Form mode's design switch, which opens the form designer's sidebar.\n design: 'Design de formulário',\n },\n redact: {\n mark: 'Marcar para tarjar',\n applyAll: 'Aplicar tarjas',\n clearAll: 'Limpar marcações',\n },\n undo: 'Desfazer',\n redo: 'Refazer',\n page: {\n next: 'Próxima página',\n previous: 'Página anterior',\n first: 'Primeira página',\n last: 'Última página',\n goTo: 'Ir para a página',\n },\n find: 'Localizar',\n shortcuts: 'Atalhos de teclado',\n notAllowed: {\n default: 'Ação não permitida: {label}',\n 'annotations-create': 'Não é permitido adicionar anotações',\n 'doc-annotate-modify': 'Não é permitido alterar anotações',\n 'doc-annotate-read': 'Não é permitido exibir anotações',\n 'doc-download': 'Não é permitido baixar',\n 'doc-forms-modify': 'Não é permitido editar campos de formulário',\n 'doc-print': 'Não é permitido imprimir',\n 'doc-text-copy': 'Não é permitido copiar',\n 'doc-text-search': 'Não é permitido pesquisar',\n },\n turnedOff: '{label} não está disponível',\n },\n passwordPrompt: {\n title: 'Senha necessária',\n required: 'Este documento é protegido por senha. Digite a senha para abri-lo.',\n incorrect: 'A senha está incorreta. Tente novamente.',\n incorrectWarning: 'Senha incorreta',\n label: 'Senha',\n placeholder: 'Digite a senha',\n cancel: 'Cancelar',\n open: 'Abrir',\n opening: 'Abrindo…',\n },\n dropToOpen: {\n label: 'Solte um PDF para abri-lo',\n },\n documentError: {\n title: 'Não foi possível abrir o documento',\n unknown: 'O documento não pôde ser aberto.',\n notFound: 'O arquivo não foi encontrado.',\n notAllowed: 'Você não tem acesso a este documento.',\n damaged: 'Este arquivo não é um PDF ou está danificado.',\n unsupported: 'Este visualizador não pode abrir este tipo de documento.',\n retry: 'Tentar novamente',\n close: 'Fechar documento',\n },\n tabs: {\n close: 'Fechar {name}',\n loading: 'Carregando',\n untitled: 'Documento {id}',\n },\n closeUnsaved: {\n title: 'Fechar sem salvar?',\n body: '“{name}” tem alterações que não foram baixadas. Elas serão perdidas.',\n cancel: 'Cancelar',\n close: 'Fechar sem salvar',\n },\n viewOnly: {\n label: 'Somente leitura',\n turnedOff: 'As ferramentas que alteram este documento estão desativadas',\n notAllowed: 'Você pode ler este documento, mas não alterá-lo',\n },\n panel: {\n close: 'Fechar',\n resize: 'Redimensionar {title}',\n },\n menu: {\n back: 'Voltar',\n },\n shortcuts: {\n document: 'Documento',\n viewing: 'Visualização',\n editing: 'Edição',\n other: 'Outros',\n },\n goToPage: {\n go: 'Ir',\n },\n panels: {\n thumbnails: 'Miniaturas',\n outline: 'Marcadores',\n attachments: 'Anexos',\n search: 'Pesquisar',\n comments: 'Comentários',\n style: 'Estilo',\n stamps: 'Carimbos',\n signatures: 'Assinaturas',\n redaction: 'Tarjas',\n measurement: 'Medições',\n formDesign: 'Design de formulário',\n switch: 'Trocar painel',\n },\n annotation: {\n comment: 'Comentário',\n highlight: 'Realce',\n underline: 'Sublinhado',\n squiggly: 'Ondulado',\n strikeout: 'Tachado',\n square: 'Quadrado',\n circle: 'Círculo',\n line: 'Linha',\n polygon: 'Polígono',\n polyline: 'Polilinha',\n ink: 'Desenho',\n freeText: 'Texto',\n stamp: 'Carimbo',\n caret: 'Sinal de inserção',\n redact: 'Tarja',\n fileAttachment: 'Anexo',\n // The style panel's labels, as the annotation kinds name them (`labelKey`), by wording:\n // one field is called different things by different kinds.\n style: {\n opacity: 'Opacidade',\n stroke: 'Traço',\n fill: 'Preenchimento',\n color: 'Cor',\n strokeWidth: 'Espessura do traço',\n border: 'Borda',\n borderStyle: 'Estilo da borda',\n borderColor: 'Cor da borda',\n borderWidth: 'Espessura da borda',\n background: 'Plano de fundo',\n outline: 'Contorno',\n lineEndings: 'Extremidades da linha',\n blendMode: 'Modo de mesclagem',\n font: 'Fonte',\n fontSize: 'Tamanho da fonte',\n textColor: 'Cor do texto',\n bold: 'Negrito',\n italic: 'Itálico',\n underline: 'Sublinhado',\n align: 'Alinhar',\n alignment: 'Alinhamento',\n label: 'Rótulo',\n labelFont: 'Fonte do rótulo',\n labelSize: 'Tamanho do rótulo',\n labelColor: 'Cor do rótulo',\n icon: 'Ícone',\n link: 'Link',\n },\n // The annotation flags (`/F`).\n flags: {\n print: 'Imprimir',\n hidden: 'Oculta',\n noView: 'Não exibir',\n toggleNoView: 'Alternar não exibir',\n readOnly: 'Somente leitura',\n locked: 'Bloqueada',\n lockedContents: 'Conteúdo bloqueado',\n noZoom: 'Sem zoom',\n noRotate: 'Sem rotação',\n invisible: 'Invisível',\n },\n borderStyles: { solid: 'Sólido', dashed: 'Tracejado', cloudy: 'Nuvem' },\n lineEndings: {\n none: 'Nenhuma',\n square: 'Quadrado',\n circle: 'Círculo',\n diamond: 'Losango',\n openArrow: 'Seta aberta',\n closedArrow: 'Seta fechada',\n butt: 'Barra',\n reverseOpenArrow: 'Seta aberta invertida',\n reverseClosedArrow: 'Seta fechada invertida',\n slash: 'Barra diagonal',\n },\n blendModes: {\n normal: 'Normal',\n multiply: 'Multiplicação',\n screen: 'Divisão',\n overlay: 'Sobrepor',\n darken: 'Escurecer',\n lighten: 'Clarear',\n colorDodge: 'Subexposição de cores',\n colorBurn: 'Superexposição de cores',\n hardLight: 'Luz direta',\n softLight: 'Luz indireta',\n difference: 'Diferença',\n exclusion: 'Exclusão',\n hue: 'Matiz',\n saturation: 'Saturação',\n color: 'Cor',\n luminosity: 'Luminosidade',\n },\n // The standard PDF fonts, by their names: a language may keep them as they are.\n fonts: {\n courier: 'Courier',\n courierBold: 'Courier Bold',\n courierBoldOblique: 'Courier Bold Oblique',\n courierOblique: 'Courier Oblique',\n helvetica: 'Helvetica',\n helveticaBold: 'Helvetica Bold',\n helveticaBoldOblique: 'Helvetica Bold Oblique',\n helveticaOblique: 'Helvetica Oblique',\n timesRoman: 'Times Roman',\n timesBold: 'Times Bold',\n timesBoldItalic: 'Times Bold Italic',\n timesItalic: 'Times Italic',\n symbol: 'Symbol',\n zapfDingbats: 'Zapf Dingbats',\n },\n alignments: { left: 'Esquerda', center: 'Centro', right: 'Direita' },\n noteIcons: {\n comment: 'Comentário',\n key: 'Chave',\n note: 'Nota',\n help: 'Ajuda',\n newParagraph: 'Novo parágrafo',\n paragraph: 'Parágrafo',\n insert: 'Inserir',\n },\n attachmentIcons: {\n pushPin: 'Tachinha',\n paperclip: 'Clipe de papel',\n graph: 'Gráfico',\n tag: 'Etiqueta',\n },\n },\n // A form field's settings, as the form plugin names them (`labelKey`).\n form: {\n settings: {\n name: 'Nome',\n tooltip: 'Dica de ferramenta',\n required: 'Obrigatório',\n readOnly: 'Somente leitura',\n noExport: 'Não exportar',\n defaultValue: 'Valor padrão',\n maxLength: 'Comprimento máximo',\n multiline: 'Várias linhas',\n password: 'Senha',\n comb: 'Um caractere por caixa',\n radiosInUnison: 'Botões com o mesmo valor são ativados juntos',\n keepOneOn: 'Manter um ativado',\n options: 'Opções',\n allowTyping: 'Permitir digitação',\n multiSelect: 'Várias escolhas',\n },\n },\n // A thumbnail's tooltip.\n thumbnails: { page: 'Página {page}' },\n // The form designer's sidebar: the fields by page, and the selected one's buttons.\n formDesign: {\n empty: 'Nenhum campo ainda. Escolha uma ferramenta de campo para adicionar um.',\n page: 'Página {page}',\n allFields: 'Todos os campos',\n buttons: 'Botões',\n boxes: 'Caixas',\n box: 'Caixa {number}',\n addButton: 'Adicionar um botão',\n addBox: 'Adicionar uma caixa',\n },\n // The style panel's own words around the properties.\n stylePanel: {\n mixed: '(misto)',\n // A color swatch that takes the color away.\n transparent: 'Transparente',\n lineStart: 'Início',\n lineEnd: 'Fim',\n empty:\n 'Escolha uma ferramenta de desenho ou selecione uma anotação para editar o estilo dela.',\n selected: 'Selecionados: {count}',\n toolDefaults: 'Padrões de {tool}',\n defaults: 'Padrões',\n },\n // The flags section of the style panel: its title, and what each flag does.\n annotationFlags: {\n title: 'Sinalizadores (/F)',\n print: 'Incluir quando a página for impressa',\n hidden: 'Some em todo lugar: tela, cliques, impressão',\n noView: 'Oculta na tela, ainda pode ser impressa',\n toggleNoView: 'Revelar uma anotação não exibida enquanto estiver selecionada',\n readOnly: 'Visível, mas não clicável',\n locked: 'Sem mover / redimensionar / excluir / mudar estilo',\n lockedContents: 'O texto não pode mudar; a geometria pode',\n noZoom: 'Tamanho constante na tela (ancorada no canto superior esquerdo)',\n noRotate: 'Fica na vertical quando a página gira',\n invisible: 'Legado: ocultar subtipos desconhecidos',\n },\n // The link editor over a selected annotation.\n linkEditor: {\n toUrl: 'Link para uma URL',\n url: 'URL',\n toPage: 'Link para uma página',\n page: 'Página',\n urlPlaceholder: 'https://…',\n pagePlaceholder: 'Número da página',\n add: 'Adicionar link',\n update: 'Atualizar link',\n },\n demo: {\n starting: 'Iniciando o visualizador…',\n opening: 'Abrindo o documento…',\n more: 'Mais',\n searchPlaceholder: 'Pesquisar no documento…',\n searchCaseSensitive: 'Diferenciar maiúsculas',\n searchWholeWord: 'Palavra inteira',\n searchRegex: 'Expressão regular',\n searchSearching: 'Pesquisando…',\n searchResults: '{count} resultados encontrados',\n searchNoResults: 'Nenhum resultado',\n searchPrevious: 'Resultado anterior',\n searchNext: 'Próximo resultado',\n searchPage: 'Página {page}',\n commentsForbidden: 'Você não tem acesso aos comentários deste documento.',\n commentsLoading: 'Carregando comentários…',\n commentsError: 'Não foi possível carregar os comentários.',\n commentsRetry: 'Tentar novamente',\n commentsEmpty:\n 'Nenhum comentário ainda. Use a ferramenta de nota para iniciar uma discussão.',\n commentsEmptyReadOnly: 'Nenhum comentário neste documento.',\n commentsAnonymous: 'Desconhecido',\n commentsPage: 'Página {page}',\n commentCount: '{count} comentário',\n commentCountPlural: '{count} comentários',\n commentsReply: 'Responder',\n commentsReplyPlaceholder: 'Responder…',\n commentsAddPlaceholder: 'Adicionar um comentário…',\n commentsDelete: 'Excluir comentário',\n commentsDeleteThread: 'Excluir discussão',\n commentsEdit: 'Editar comentário',\n commentsStatus: 'Status',\n commentsStatusNone: 'Sem status',\n commentsStatusAccepted: 'Aceito',\n commentsStatusRejected: 'Rejeitado',\n commentsStatusCancelled: 'Cancelado',\n commentsStatusCompleted: 'Concluído',\n empty: 'Ainda não há nada neste painel de demonstração.',\n page: 'Página {current} de {total}',\n goToPage: 'Ir para a página',\n cancel: 'Cancelar',\n pageBadge: 'pág. {page}',\n redactionEmpty: 'Nenhuma tarja pendente. Use a ferramenta Tarjar para marcar texto ou áreas.',\n redactionArea: 'Marcação de área',\n redactionText: 'Marcação de texto',\n redactionRemove: 'Remover marcação',\n redactConfirmTitle: 'Aplicar tarjas?',\n redactConfirmBody:\n 'Remover permanentemente o conteúdo sob {count} marcações de tarja. Esta ação não pode ser desfeita.',\n redactConfirmCollateral: '{count} outras anotações também serão removidas.',\n redactApply: 'Aplicar',\n redactApplying: 'Aplicando…',\n formatLabel: 'Formato',\n fieldSettingsTitle: 'Campo',\n fieldOptionLabel: 'Rótulo',\n fieldOptionValue: 'Valor',\n fieldOptionAdd: 'Adicionar opção',\n fieldOptionRemove: 'Remover opção',\n fieldNone: 'Nenhum',\n redactLabelTitle: 'Rótulo da tarja',\n redactLabelPlaceholder: 'ex.: TARJADO',\n redactLabelRepeat: 'Repetir rótulo em toda a região',\n stampsAll: 'Todos os carimbos',\n stampsLoading: 'Carregando carimbos…',\n stampsEmpty:\n 'Nenhum carimbo ainda. Importe um PDF para transformar cada página dele em um carimbo.',\n stampsRemoveStamp: 'Remover carimbo',\n stampsArmedHint: 'Clique em uma página para posicionar o carimbo.',\n stampsImport: 'Importar PDF…',\n stampsImporting: 'Importando…',\n stampsImportHint: 'Importe um PDF como biblioteca de carimbos — cada página vira um carimbo.',\n stampsRemoveLibrary: 'Remover biblioteca',\n stampsExportLibrary: 'Exportar biblioteca como PDF',\n stampsCustomLibrary: 'Meus carimbos',\n stampsCustomLabel: 'Carimbo personalizado',\n stampsError: 'Não foi possível carregar os carimbos integrados.',\n stampsArmError: 'Não foi possível ativar esse carimbo.',\n stampsImportError: 'Não foi possível importar esse PDF como biblioteca de carimbos.',\n quickStampsLabel: 'Carimbos rápidos',\n signaturesEmpty: 'Nenhuma assinatura ainda. Crie uma para assinar.',\n signaturesNew: 'Nova assinatura…',\n signaturesArmedHint:\n 'Clique em um campo de assinatura para assiná-lo, ou em qualquer lugar de uma página para posicionar a marca.',\n signaturesTargetHint: 'Escolha uma marca para o campo selecionado.',\n signaturesInDocument: 'Neste documento',\n signaturesNone: 'Este documento não tem campos de assinatura.',\n signaturesValidate: 'Validar',\n signaturesValidating: 'Validando…',\n signaturesSigned: 'Assinado',\n signaturesUnsigned: 'Não assinado',\n signaturesRename: 'Renomear',\n signaturesRemove: 'Remover',\n signaturesExport: 'Exportar como PDF',\n signaturesAddInitials: 'Adicionar iniciais',\n signatureLabel: 'Assinatura',\n initialsLabel: 'Iniciais',\n makerTitle: 'Nova assinatura',\n makerName: 'Nome',\n makerNamePlaceholder: 'Seu nome',\n makerDraw: 'Desenhar',\n makerType: 'Digitar',\n makerUpload: 'Carregar',\n makerTypePlaceholder: 'Digite seu nome',\n makerFont: 'Fonte',\n makerUploadHint: 'Escolha um PNG, JPEG ou PDF de uma página',\n makerClear: 'Limpar',\n makerOptional: '(opcional)',\n makerSave: 'Salvar',\n makerSaving: 'Salvando…',\n makerError: 'Não foi possível salvar a assinatura.',\n signTitle: 'Assinar este campo',\n signReason: 'Motivo',\n signLocation: 'Local',\n signKind: 'O que pode mudar depois',\n signKindApproval:\n 'Assinatura de aprovação — o preenchimento de formulários e outras assinaturas continuam válidos',\n signKindCertifyAnnotate:\n 'Certificar — permitir comentários, preenchimento de formulários e assinaturas',\n signKindCertifyFill:\n 'Certificar — permitir somente preenchimento de formulários e assinaturas',\n signKindCertifyLocked: 'Certificar — não permitir alterações',\n signButton: 'Assinar',\n signSigning: 'Assinando…',\n signFill: 'Posicionar sem assinar',\n signError: 'Não foi possível assinar o campo.',\n inspectTitle: 'Assinatura',\n inspectSigner: 'Assinado por',\n inspectReason: 'Motivo',\n inspectLocation: 'Local',\n inspectTime: 'Data e hora',\n inspectIntegrity: 'Documento',\n inspectCryptography: 'Assinatura',\n inspectTrust: 'Signatário',\n inspectChanges: 'Alterações posteriores',\n inspectDownload: 'Baixar versão assinada',\n verdictValid: 'Válida',\n verdictValidUntrusted: 'Válida, signatário não confiável',\n verdictInvalid: 'Inválida — documento alterado após a assinatura',\n verdictWillInvalidate: 'Válida, inválida ao salvar',\n signaturesInvalidating:\n 'Esta alteração invalidará {field} quando o documento for salvo. Desfaça-a para manter a assinatura.',\n verdictIndeterminate: 'Não foi possível verificar',\n verdictUnchanged: 'Nenhuma',\n verdictRestored: 'Alterado e depois restaurado',\n inspectLaterRevisions: 'Revisões após a assinatura',\n verdictPermitted: 'Permitidas',\n verdictForbidden: 'Não permitidas',\n },\n },\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sheet-BDsa_Sup.cjs","names":[],"sources":["../src/ui/screen-edges.ts","../src/ui/viewer-layer.ts","../src/ui/sheet-rest.ts","../src/ui/sheet.tsx"],"sourcesContent":["/**\n * Which edges of the window the viewer reaches, and the padding that keeps\n * what sits at those edges clear of the notch, the rounded corners and the\n * home bar. The padding is the browser's `env(safe-area-inset-*)`, which is\n * zero unless the page lets content under those areas (`viewport-fit=cover`),\n * so it changes nothing on an ordinary page. The viewer reaches an edge when\n * its box is at that edge of the window or past it, as in full screen or as\n * the whole page of a phone app.\n */\n/** For each edge of the window, whether the viewer reaches it. */\nexport interface ScreenEdges {\n readonly top: boolean;\n readonly right: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n}\n\nexport const NO_SCREEN_EDGES: ScreenEdges = {\n top: false,\n right: false,\n bottom: false,\n left: false,\n};\n\n/** A box in window px. */\nexport interface ScreenBox {\n readonly left: number;\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n}\n\n/** How close to the window's edge a box counts as reaching it, for rounding. */\nconst EDGE_TOLERANCE_PX = 1;\n\n/** The edges of a `width` × `height` window that `box` reaches while some of it is on screen. */\nexport function screenEdgesOf(\n box: ScreenBox,\n view: { readonly width: number; readonly height: number },\n): ScreenEdges {\n const across = box.right > 0 && box.left < view.width;\n const down = box.bottom > 0 && box.top < view.height;\n return {\n top: across && box.top <= EDGE_TOLERANCE_PX && box.bottom > 0,\n right: down && box.right >= view.width - EDGE_TOLERANCE_PX && box.left < view.width,\n bottom: across && box.bottom >= view.height - EDGE_TOLERANCE_PX && box.top < view.height,\n left: down && box.left <= EDGE_TOLERANCE_PX && box.right > 0,\n };\n}\n\nexport const sameScreenEdges = (left: ScreenEdges, right: ScreenEdges): boolean =>\n left.top === right.top &&\n left.right === right.right &&\n left.bottom === right.bottom &&\n left.left === right.left;\n\n/** The padding of each side in `sides` whose edge the viewer reaches. */\nexport interface SafeAreaPadding {\n paddingTop?: string;\n paddingRight?: string;\n paddingBottom?: string;\n paddingLeft?: string;\n}\n\nconst PADDING: Readonly<Record<keyof ScreenEdges, keyof SafeAreaPadding>> = {\n top: 'paddingTop',\n right: 'paddingRight',\n bottom: 'paddingBottom',\n left: 'paddingLeft',\n};\n\n/** The safe-area padding for the reached edges among `sides` (default all four), as style properties. */\nexport function safeAreaPaddingOf(\n edges: ScreenEdges,\n sides: readonly (keyof ScreenEdges)[] = ['top', 'right', 'bottom', 'left'],\n): SafeAreaPadding {\n const padding: SafeAreaPadding = {};\n for (const side of sides) {\n if (edges[side]) padding[PADDING[side]] = `env(safe-area-inset-${side}, 0px)`;\n }\n return padding;\n}\n\n/** The window's size, without its scrollbars. */\nexport function windowSizeOf(element: Element): { width: number; height: number } {\n const { clientWidth, clientHeight } = element.ownerDocument.documentElement;\n return { width: clientWidth, height: clientHeight };\n}\n","/**\n * What opens over the whole viewer: a layer the size of the viewer's box on\n * screen, in the browser's top layer, where sheets and dialogs open. In the\n * top layer nothing the viewer draws covers it, and what opens later (a menu\n * from a sheet, a dialog from a panel) sits above what opened before. And\n * what holds the keyboard while it's open (a sheet, a dialog): it takes\n * focus, keeps Tab inside it, closes on Escape, and gives focus back to what\n * had it before, the button that opened it. An overlay panel takes focus the\n * same way but lets Tab move on, so the rest of the viewer stays in reach.\n */\nimport {\n attachFocusTrap,\n deepActiveElementOf,\n moveFocusInto,\n observeClientGeometry,\n} from '@embedpdf/web';\n\nimport { screenEdgesOf, windowSizeOf, type ScreenEdges } from './screen-edges';\n\n/** The `popover` attribute, which React's types don't list yet. */\nexport const POPOVER = { popover: 'manual' } as Record<string, string>;\n\n/** The custom element's root: the viewer's box. */\nconst VIEWER_ROOT_SELECTOR = '[data-embedpdf-root]';\n\n/** What another surface that holds focus is marked with: a press in it is not a press outside. */\nexport const MODAL_SELECTOR = '[aria-modal=\"true\"]';\n\n/**\n * What the viewer's root is marked with: it takes focus on a press that lands on nothing that\n * takes focus itself (the pages), so the viewer's keys reach it from there.\n */\nexport const FOCUS_ROOT_ATTRIBUTE = 'data-epdf-focus-root';\n\n/** Place `element` (`position: fixed`) at a box in window px. */\nfunction placeFixed(\n element: HTMLElement,\n box: { left: number; top: number; width: number; height: number },\n): void {\n element.style.left = `${box.left}px`;\n element.style.top = `${box.top}px`;\n element.style.width = `${box.width}px`;\n element.style.height = `${box.height}px`;\n // Without the top layer, `position: fixed` starts at the viewer's box (its `contain`): move by\n // however far from the window's origin the layer landed.\n const landed = element.getBoundingClientRect();\n if (Math.abs(landed.left - box.left) > 0.5 || Math.abs(landed.top - box.top) > 0.5) {\n element.style.left = `${2 * box.left - landed.left}px`;\n element.style.top = `${2 * box.top - landed.top}px`;\n }\n}\n\n/**\n * Show `layer` in the top layer over the part of the viewer on screen, and keep it there as the\n * viewer or the window resizes or scrolls. `onPlace` hears which edges of the window the viewer\n * reaches, each time the layer is placed. Returns the stop, which hides the layer.\n */\nexport function attachViewerLayer(\n layer: HTMLElement,\n onPlace?: (edges: ScreenEdges) => void,\n): () => void {\n const root = layer.parentElement?.closest(VIEWER_ROOT_SELECTOR) ?? null;\n if (typeof layer.showPopover === 'function') layer.showPopover();\n let placed = '';\n const place = () => {\n const view = windowSizeOf(layer);\n const rect = root?.getBoundingClientRect() ?? {\n left: 0,\n top: 0,\n right: view.width,\n bottom: view.height,\n };\n const left = Math.max(0, rect.left);\n const top = Math.max(0, rect.top);\n const box = {\n left,\n top,\n width: Math.max(0, Math.min(view.width, rect.right) - left),\n height: Math.max(0, Math.min(view.height, rect.bottom) - top),\n };\n // Scrolling inside the layer reaches here too: only a move of the viewer changes anything.\n const key = `${box.left},${box.top},${box.width},${box.height},${view.width},${view.height}`;\n if (key === placed) return;\n placed = key;\n placeFixed(layer, box);\n onPlace?.(screenEdgesOf(rect, view));\n };\n place();\n const resizes = new ResizeObserver(place);\n if (root) resizes.observe(root);\n const stopGeometry = observeClientGeometry(place);\n return () => {\n stopGeometry();\n resizes.disconnect();\n if (typeof layer.hidePopover === 'function' && layer.matches(':popover-open')) {\n layer.hidePopover();\n }\n };\n}\n\nexport interface HeldFocus {\n /** Stop holding focus, leaving it where it is. */\n standDown(): void;\n /** Stop holding focus, and give it back to what had it before when it's still in `container`. */\n release(): void;\n}\n\n/**\n * Hold the keyboard in `container` until released: focus moves into it unless it's there\n * already (to `initialFocus`, else its first control), so a field that took the cursor as it\n * appeared keeps it; Tab and Shift+Tab stay inside it, and Escape calls `onEscape`. With\n * `trap: false` Tab moves on past it, as it does past anything else in the viewer. Releasing\n * gives focus back to what had it before, unless the user has moved it elsewhere: a press on\n * the pages, which puts focus on the viewer's root, doesn't count.\n */\nexport function holdFocus(\n container: HTMLElement,\n options: {\n readonly onEscape: () => void;\n readonly initialFocus?: HTMLElement | null;\n readonly trap?: boolean;\n },\n): HeldFocus {\n const doc = container.ownerDocument;\n const before = deepActiveElementOf(doc) as HTMLElement | null;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape' || event.defaultPrevented) return;\n event.preventDefault();\n // Escape closes this, not what it opened over.\n event.stopPropagation();\n options.onEscape();\n };\n container.addEventListener('keydown', onKeyDown);\n let releaseTrap: (() => void) | null = null;\n if (options.trap === false) {\n moveFocusInto(container, options.initialFocus);\n } else {\n releaseTrap = attachFocusTrap(container, {\n initialFocus: options.initialFocus,\n returnFocus: false,\n });\n }\n const standDown = () => {\n releaseTrap?.();\n releaseTrap = null;\n container.removeEventListener('keydown', onKeyDown);\n };\n return {\n standDown,\n release: () => {\n standDown();\n const active = deepActiveElementOf(doc);\n const nowhere =\n active === null || container.contains(active) || active.hasAttribute(FOCUS_ROOT_ATTRIBUTE);\n if (before?.isConnected && nowhere) before.focus();\n },\n };\n}\n","/**\n * Where a sheet comes to rest after its handle is let go: at one of the\n * heights it rests at, or closed. A flick moves it a whole step, down to the\n * next lower height (closing from the lowest) or up to the next higher one;\n * a slow drag settles at the nearest height, and closes when the sheet was\n * dragged below half of the lowest.\n */\n\n/** A release faster than this, in px per second, is a flick. */\nexport const SHEET_FLICK_PX_PER_S = 500;\n\n/** How much of the viewer's height a panel's sheet opens at. */\nexport const PANEL_SHEET_OPEN_FRACTION = 0.5;\n\n/** Px a sheet leaves above itself at its tallest, so the pages show it's a sheet. */\nexport const SHEET_TOP_CLEARANCE_PX = 40;\n\n/**\n * The height a sheet dragged to `height` comes to rest at, one of `heights` (ascending), or null\n * when it closes. `velocity` is the release speed in px per second, downward positive.\n */\nexport function sheetRestOf(\n heights: readonly number[],\n height: number,\n velocity: number,\n): number | null {\n if (heights.length === 0) return null;\n if (velocity >= SHEET_FLICK_PX_PER_S) {\n const lower = heights.filter((rest) => rest < height - 1);\n return lower.length > 0 ? lower[lower.length - 1]! : null;\n }\n if (velocity <= -SHEET_FLICK_PX_PER_S) {\n return heights.find((rest) => rest > height + 1) ?? heights[heights.length - 1]!;\n }\n if (height < heights[0]! / 2) return null;\n return heights.reduce((nearest, rest) =>\n Math.abs(rest - height) < Math.abs(nearest - height) ? rest : nearest,\n );\n}\n\n/** The heights a panel's sheet rests at in a viewer `viewerHeight` px tall: half of it, and nearly all. */\nexport function panelSheetHeightsOf(viewerHeight: number): readonly number[] {\n const tallest = Math.max(0, Math.round(viewerHeight - SHEET_TOP_CLEARANCE_PX));\n const open = Math.min(tallest, Math.round(viewerHeight * PANEL_SHEET_OPEN_FRACTION));\n return open < tallest ? [open, tallest] : [tallest];\n}\n","/**\n * A sheet: what a panel or a menu is on a phone. It slides up from the bottom\n * of the viewer, over the pages, in a layer over the whole viewer\n * (`viewer-layer.ts`); the viewer above it dims, and a tap there closes it.\n * Its handle drags it taller or shorter, or down to close it, and a flick\n * moves it a whole step (`sheet-rest.ts`). It keeps clear of the home bar and\n * the screen's rounded corners when the viewer reaches the screen's edge.\n * A sheet takes focus when it opens, keeps Tab inside it, closes on Escape\n * and gives focus back to the button that opened it; a menu's sheet leaves\n * the keyboard to its menu. A sheet that holds a list closes when one of its\n * items is picked ({@link useCloseOnPick}).\n */\nimport { computeReleaseVelocity, observeOutsidePress } from '@embedpdf/web';\nimport {\n createContext,\n useContext,\n useLayoutEffect,\n useRef,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\n\nimport { safeAreaPaddingOf } from './screen-edges';\nimport { SHEET_TOP_CLEARANCE_PX, panelSheetHeightsOf, sheetRestOf } from './sheet-rest';\nimport { MODAL_SELECTOR, POPOVER, attachViewerLayer, holdFocus } from './viewer-layer';\n\n/** A press that starts on one of these in the handle's row is the control's, not a drag. */\nconst CONTROL_SELECTOR =\n 'button, a[href], input, select, textarea, [role=\"tab\"], [contenteditable]:not([contenteditable=\"false\"])';\n\n/** The dimmed viewer behind a sheet or a dialog. */\nexport const SCRIM_CLASS = 'bg-black/30 transition-opacity duration-200 starting:opacity-0';\n\nconst NO_PICK = () => {};\n\nconst CloseOnPickContext = createContext<() => void>(NO_PICK);\n\n/** Gives what's inside a sheet or an overlay the close it runs when one of its items is picked. */\nexport const CloseOnPickProvider = CloseOnPickContext.Provider;\n\n/**\n * What a list's item runs when it's picked: it closes the sheet or the overlay the list is in,\n * so you see where it took you. It does nothing in a docked panel, or in one that isn't a list.\n */\nexport function useCloseOnPick(): () => void {\n return useContext(CloseOnPickContext);\n}\n\n/** Whether a press landed in another surface that holds focus, like a dialog opened over this one. */\nconst pressedInOtherModal = (event: PointerEvent, own: Element): boolean =>\n event\n .composedPath()\n .some((node) => node instanceof Element && node !== own && node.matches(MODAL_SELECTOR));\n\nexport interface SheetProps {\n /** Names the sheet for assistive technology. */\n readonly label: string;\n readonly onClose: () => void;\n /**\n * `'content'`: as tall as what's in it, like a menu. `'panel'`: opens at half the viewer's\n * height, and drags up to nearly all of it. Default `'content'`.\n */\n readonly size?: 'content' | 'panel';\n /** It holds a list: picking an item ({@link useCloseOnPick}) closes it. */\n readonly list?: boolean;\n /**\n * Whether it holds the keyboard (default true). A menu's sheet doesn't: its menu takes focus\n * and gives it back.\n */\n readonly trapFocus?: boolean;\n /** Drawn under the handle, above the part that scrolls; dragging it moves the sheet too. */\n readonly header?: ReactNode;\n /** The sheet's part name, for page CSS through `::part()`, when it is one: a panel's `panel`. */\n readonly part?: string;\n /** `data-*` attributes for the sheet, by their names without `data-`. */\n readonly data?: Readonly<Record<string, string>>;\n readonly children: ReactNode;\n}\n\ninterface Drag {\n readonly pointerId: number;\n readonly startY: number;\n readonly startHeight: number;\n /** The heights it can rest at, ascending. */\n readonly heights: readonly number[];\n readonly samples: { t: number; x: number; y: number }[];\n height: number;\n}\n\n/** `data` as the `data-*` attributes it names. */\nconst dataAttributesOf = (data: Readonly<Record<string, string>> | undefined) =>\n Object.fromEntries(Object.entries(data ?? {}).map(([name, value]) => [`data-${name}`, value]));\n\n/** How many pointer samples a drag keeps for its release speed. */\nconst DRAG_SAMPLES = 8;\n\nexport function Sheet({\n label,\n onClose,\n size = 'content',\n list = false,\n trapFocus = true,\n header,\n part,\n data,\n children,\n}: SheetProps) {\n const layer = useRef<HTMLDivElement>(null);\n const sheet = useRef<HTMLDivElement>(null);\n const close = useRef(onClose);\n close.current = onClose;\n /** Which of its heights a panel's sheet rests at: the first (open) or a taller one. */\n const restIndex = useRef(0);\n const drag = useRef<Drag | null>(null);\n\n /** The heights it rests at now: a panel's from the viewer's height, a menu's as tall as it is. */\n const heightsNow = (): readonly number[] =>\n size === 'panel'\n ? panelSheetHeightsOf(layer.current?.offsetHeight ?? 0)\n : [sheet.current?.offsetHeight ?? 0];\n\n /** Show the sheet dragged to `height` (its top that far above the viewer's bottom). */\n const show = (height: number, heights: readonly number[]) => {\n const element = sheet.current;\n if (!element || heights.length === 0) return;\n const lowest = heights[0]!;\n const tallest = heights[heights.length - 1]!;\n if (size === 'panel') element.style.height = `${Math.min(tallest, Math.max(lowest, height))}px`;\n const below = Math.max(0, lowest - height);\n element.style.translate = below > 0 ? `0 ${below}px` : '';\n };\n\n useLayoutEffect(() => {\n const layerElement = layer.current;\n const sheetElement = sheet.current;\n if (!layerElement || !sheetElement) return;\n const stopLayer = attachViewerLayer(layerElement, (edges) => {\n const padding = safeAreaPaddingOf(edges, ['right', 'bottom', 'left']);\n sheetElement.style.paddingLeft = padding.paddingLeft ?? '';\n sheetElement.style.paddingRight = padding.paddingRight ?? '';\n sheetElement.style.paddingBottom = padding.paddingBottom ?? '';\n sheetElement.style.maxHeight = `${Math.max(0, layerElement.offsetHeight - SHEET_TOP_CLEARANCE_PX)}px`;\n if (size === 'panel' && !drag.current) {\n const heights = panelSheetHeightsOf(layerElement.offsetHeight);\n show(heights[Math.min(restIndex.current, heights.length - 1)]!, heights);\n }\n });\n const held = trapFocus ? holdFocus(sheetElement, { onEscape: () => close.current() }) : null;\n // A press on the viewer above the sheet is the scrim's click; one outside the viewer closes it too.\n const stopOutside = observeOutsidePress(layerElement, (event) => {\n if (!pressedInOtherModal(event, sheetElement)) close.current();\n });\n return () => {\n stopOutside();\n held?.release();\n stopLayer();\n };\n // The sheet opens once; it closes by unmounting.\n }, []);\n\n const onGripDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.pointerType === 'mouse' && event.button !== 0) return;\n if ((event.target as Element).closest(CONTROL_SELECTOR)) return;\n const element = sheet.current;\n if (!element) return;\n event.currentTarget.setPointerCapture(event.pointerId);\n const startHeight = element.offsetHeight;\n drag.current = {\n pointerId: event.pointerId,\n startY: event.clientY,\n startHeight,\n heights: heightsNow(),\n samples: [{ t: event.timeStamp, x: event.clientX, y: event.clientY }],\n height: startHeight,\n };\n element.setAttribute('data-dragging', '');\n };\n\n const onGripMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n const current = drag.current;\n if (!current || current.pointerId !== event.pointerId) return;\n current.height = current.startHeight - (event.clientY - current.startY);\n current.samples.push({ t: event.timeStamp, x: event.clientX, y: event.clientY });\n if (current.samples.length > DRAG_SAMPLES) current.samples.shift();\n show(current.height, current.heights);\n };\n\n const onGripUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n const current = drag.current;\n if (!current || current.pointerId !== event.pointerId) return;\n drag.current = null;\n sheet.current?.removeAttribute('data-dragging');\n const cancelled = event.type === 'pointercancel';\n const velocity = cancelled\n ? 0\n : (computeReleaseVelocity(current.samples, event.timeStamp)?.vy ?? 0);\n const rest = cancelled\n ? current.heights[restIndex.current]!\n : sheetRestOf(current.heights, current.height, velocity);\n if (rest === null) {\n close.current();\n return;\n }\n restIndex.current = Math.max(0, current.heights.indexOf(rest));\n show(rest, current.heights);\n };\n\n return (\n <div\n ref={layer}\n {...POPOVER}\n data-epdf-layer=\"\"\n className=\"text-fg m-0 overflow-hidden border-0 bg-transparent p-0 open:flex open:flex-col\"\n style={{ position: 'fixed', inset: 'auto', maxWidth: 'none', maxHeight: 'none' }}\n >\n <div\n aria-hidden=\"true\"\n className={`min-h-0 flex-1 ${SCRIM_CLASS}`}\n onClick={() => close.current()}\n />\n <div\n ref={sheet}\n role={trapFocus ? 'dialog' : undefined}\n aria-modal={trapFocus ? true : undefined}\n aria-label={trapFocus ? label : undefined}\n part={part}\n {...dataAttributesOf(data)}\n data-epdf-sheet=\"\"\n className=\"border-border-subtle bg-elevated starting:translate-y-full data-dragging:transition-none relative flex w-full shrink-0 flex-col rounded-t-2xl border-t shadow-2xl transition-[translate,height] duration-200 ease-out motion-reduce:transition-none\"\n >\n <div\n className=\"shrink-0 touch-pan-x select-none\"\n onPointerDown={onGripDown}\n onPointerMove={onGripMove}\n onPointerUp={onGripUp}\n onPointerCancel={onGripUp}\n >\n <div\n data-epdf-sheet-handle=\"\"\n className=\"flex h-6 cursor-grab items-center justify-center active:cursor-grabbing\"\n >\n <span className=\"bg-border-strong h-1 w-10 rounded-full\" />\n </div>\n {header}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden overscroll-contain\">\n <CloseOnPickProvider value={list ? () => close.current() : NO_PICK}>\n {children}\n </CloseOnPickProvider>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sheet-R6XDgyEf.js","names":[],"sources":["../src/ui/screen-edges.ts","../src/ui/viewer-layer.ts","../src/ui/sheet-rest.ts","../src/ui/sheet.tsx"],"sourcesContent":["/**\n * Which edges of the window the viewer reaches, and the padding that keeps\n * what sits at those edges clear of the notch, the rounded corners and the\n * home bar. The padding is the browser's `env(safe-area-inset-*)`, which is\n * zero unless the page lets content under those areas (`viewport-fit=cover`),\n * so it changes nothing on an ordinary page. The viewer reaches an edge when\n * its box is at that edge of the window or past it, as in full screen or as\n * the whole page of a phone app.\n */\n/** For each edge of the window, whether the viewer reaches it. */\nexport interface ScreenEdges {\n readonly top: boolean;\n readonly right: boolean;\n readonly bottom: boolean;\n readonly left: boolean;\n}\n\nexport const NO_SCREEN_EDGES: ScreenEdges = {\n top: false,\n right: false,\n bottom: false,\n left: false,\n};\n\n/** A box in window px. */\nexport interface ScreenBox {\n readonly left: number;\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n}\n\n/** How close to the window's edge a box counts as reaching it, for rounding. */\nconst EDGE_TOLERANCE_PX = 1;\n\n/** The edges of a `width` × `height` window that `box` reaches while some of it is on screen. */\nexport function screenEdgesOf(\n box: ScreenBox,\n view: { readonly width: number; readonly height: number },\n): ScreenEdges {\n const across = box.right > 0 && box.left < view.width;\n const down = box.bottom > 0 && box.top < view.height;\n return {\n top: across && box.top <= EDGE_TOLERANCE_PX && box.bottom > 0,\n right: down && box.right >= view.width - EDGE_TOLERANCE_PX && box.left < view.width,\n bottom: across && box.bottom >= view.height - EDGE_TOLERANCE_PX && box.top < view.height,\n left: down && box.left <= EDGE_TOLERANCE_PX && box.right > 0,\n };\n}\n\nexport const sameScreenEdges = (left: ScreenEdges, right: ScreenEdges): boolean =>\n left.top === right.top &&\n left.right === right.right &&\n left.bottom === right.bottom &&\n left.left === right.left;\n\n/** The padding of each side in `sides` whose edge the viewer reaches. */\nexport interface SafeAreaPadding {\n paddingTop?: string;\n paddingRight?: string;\n paddingBottom?: string;\n paddingLeft?: string;\n}\n\nconst PADDING: Readonly<Record<keyof ScreenEdges, keyof SafeAreaPadding>> = {\n top: 'paddingTop',\n right: 'paddingRight',\n bottom: 'paddingBottom',\n left: 'paddingLeft',\n};\n\n/** The safe-area padding for the reached edges among `sides` (default all four), as style properties. */\nexport function safeAreaPaddingOf(\n edges: ScreenEdges,\n sides: readonly (keyof ScreenEdges)[] = ['top', 'right', 'bottom', 'left'],\n): SafeAreaPadding {\n const padding: SafeAreaPadding = {};\n for (const side of sides) {\n if (edges[side]) padding[PADDING[side]] = `env(safe-area-inset-${side}, 0px)`;\n }\n return padding;\n}\n\n/** The window's size, without its scrollbars. */\nexport function windowSizeOf(element: Element): { width: number; height: number } {\n const { clientWidth, clientHeight } = element.ownerDocument.documentElement;\n return { width: clientWidth, height: clientHeight };\n}\n","/**\n * What opens over the whole viewer: a layer the size of the viewer's box on\n * screen, in the browser's top layer, where sheets and dialogs open. In the\n * top layer nothing the viewer draws covers it, and what opens later (a menu\n * from a sheet, a dialog from a panel) sits above what opened before. And\n * what holds the keyboard while it's open (a sheet, a dialog): it takes\n * focus, keeps Tab inside it, closes on Escape, and gives focus back to what\n * had it before, the button that opened it. An overlay panel takes focus the\n * same way but lets Tab move on, so the rest of the viewer stays in reach.\n */\nimport {\n attachFocusTrap,\n deepActiveElementOf,\n moveFocusInto,\n observeClientGeometry,\n} from '@embedpdf/web';\n\nimport { screenEdgesOf, windowSizeOf, type ScreenEdges } from './screen-edges';\n\n/** The `popover` attribute, which React's types don't list yet. */\nexport const POPOVER = { popover: 'manual' } as Record<string, string>;\n\n/** The custom element's root: the viewer's box. */\nconst VIEWER_ROOT_SELECTOR = '[data-embedpdf-root]';\n\n/** What another surface that holds focus is marked with: a press in it is not a press outside. */\nexport const MODAL_SELECTOR = '[aria-modal=\"true\"]';\n\n/**\n * What the viewer's root is marked with: it takes focus on a press that lands on nothing that\n * takes focus itself (the pages), so the viewer's keys reach it from there.\n */\nexport const FOCUS_ROOT_ATTRIBUTE = 'data-epdf-focus-root';\n\n/** Place `element` (`position: fixed`) at a box in window px. */\nfunction placeFixed(\n element: HTMLElement,\n box: { left: number; top: number; width: number; height: number },\n): void {\n element.style.left = `${box.left}px`;\n element.style.top = `${box.top}px`;\n element.style.width = `${box.width}px`;\n element.style.height = `${box.height}px`;\n // Without the top layer, `position: fixed` starts at the viewer's box (its `contain`): move by\n // however far from the window's origin the layer landed.\n const landed = element.getBoundingClientRect();\n if (Math.abs(landed.left - box.left) > 0.5 || Math.abs(landed.top - box.top) > 0.5) {\n element.style.left = `${2 * box.left - landed.left}px`;\n element.style.top = `${2 * box.top - landed.top}px`;\n }\n}\n\n/**\n * Show `layer` in the top layer over the part of the viewer on screen, and keep it there as the\n * viewer or the window resizes or scrolls. `onPlace` hears which edges of the window the viewer\n * reaches, each time the layer is placed. Returns the stop, which hides the layer.\n */\nexport function attachViewerLayer(\n layer: HTMLElement,\n onPlace?: (edges: ScreenEdges) => void,\n): () => void {\n const root = layer.parentElement?.closest(VIEWER_ROOT_SELECTOR) ?? null;\n if (typeof layer.showPopover === 'function') layer.showPopover();\n let placed = '';\n const place = () => {\n const view = windowSizeOf(layer);\n const rect = root?.getBoundingClientRect() ?? {\n left: 0,\n top: 0,\n right: view.width,\n bottom: view.height,\n };\n const left = Math.max(0, rect.left);\n const top = Math.max(0, rect.top);\n const box = {\n left,\n top,\n width: Math.max(0, Math.min(view.width, rect.right) - left),\n height: Math.max(0, Math.min(view.height, rect.bottom) - top),\n };\n // Scrolling inside the layer reaches here too: only a move of the viewer changes anything.\n const key = `${box.left},${box.top},${box.width},${box.height},${view.width},${view.height}`;\n if (key === placed) return;\n placed = key;\n placeFixed(layer, box);\n onPlace?.(screenEdgesOf(rect, view));\n };\n place();\n const resizes = new ResizeObserver(place);\n if (root) resizes.observe(root);\n const stopGeometry = observeClientGeometry(place);\n return () => {\n stopGeometry();\n resizes.disconnect();\n if (typeof layer.hidePopover === 'function' && layer.matches(':popover-open')) {\n layer.hidePopover();\n }\n };\n}\n\nexport interface HeldFocus {\n /** Stop holding focus, leaving it where it is. */\n standDown(): void;\n /** Stop holding focus, and give it back to what had it before when it's still in `container`. */\n release(): void;\n}\n\n/**\n * Hold the keyboard in `container` until released: focus moves into it unless it's there\n * already (to `initialFocus`, else its first control), so a field that took the cursor as it\n * appeared keeps it; Tab and Shift+Tab stay inside it, and Escape calls `onEscape`. With\n * `trap: false` Tab moves on past it, as it does past anything else in the viewer. Releasing\n * gives focus back to what had it before, unless the user has moved it elsewhere: a press on\n * the pages, which puts focus on the viewer's root, doesn't count.\n */\nexport function holdFocus(\n container: HTMLElement,\n options: {\n readonly onEscape: () => void;\n readonly initialFocus?: HTMLElement | null;\n readonly trap?: boolean;\n },\n): HeldFocus {\n const doc = container.ownerDocument;\n const before = deepActiveElementOf(doc) as HTMLElement | null;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Escape' || event.defaultPrevented) return;\n event.preventDefault();\n // Escape closes this, not what it opened over.\n event.stopPropagation();\n options.onEscape();\n };\n container.addEventListener('keydown', onKeyDown);\n let releaseTrap: (() => void) | null = null;\n if (options.trap === false) {\n moveFocusInto(container, options.initialFocus);\n } else {\n releaseTrap = attachFocusTrap(container, {\n initialFocus: options.initialFocus,\n returnFocus: false,\n });\n }\n const standDown = () => {\n releaseTrap?.();\n releaseTrap = null;\n container.removeEventListener('keydown', onKeyDown);\n };\n return {\n standDown,\n release: () => {\n standDown();\n const active = deepActiveElementOf(doc);\n const nowhere =\n active === null || container.contains(active) || active.hasAttribute(FOCUS_ROOT_ATTRIBUTE);\n if (before?.isConnected && nowhere) before.focus();\n },\n };\n}\n","/**\n * Where a sheet comes to rest after its handle is let go: at one of the\n * heights it rests at, or closed. A flick moves it a whole step, down to the\n * next lower height (closing from the lowest) or up to the next higher one;\n * a slow drag settles at the nearest height, and closes when the sheet was\n * dragged below half of the lowest.\n */\n\n/** A release faster than this, in px per second, is a flick. */\nexport const SHEET_FLICK_PX_PER_S = 500;\n\n/** How much of the viewer's height a panel's sheet opens at. */\nexport const PANEL_SHEET_OPEN_FRACTION = 0.5;\n\n/** Px a sheet leaves above itself at its tallest, so the pages show it's a sheet. */\nexport const SHEET_TOP_CLEARANCE_PX = 40;\n\n/**\n * The height a sheet dragged to `height` comes to rest at, one of `heights` (ascending), or null\n * when it closes. `velocity` is the release speed in px per second, downward positive.\n */\nexport function sheetRestOf(\n heights: readonly number[],\n height: number,\n velocity: number,\n): number | null {\n if (heights.length === 0) return null;\n if (velocity >= SHEET_FLICK_PX_PER_S) {\n const lower = heights.filter((rest) => rest < height - 1);\n return lower.length > 0 ? lower[lower.length - 1]! : null;\n }\n if (velocity <= -SHEET_FLICK_PX_PER_S) {\n return heights.find((rest) => rest > height + 1) ?? heights[heights.length - 1]!;\n }\n if (height < heights[0]! / 2) return null;\n return heights.reduce((nearest, rest) =>\n Math.abs(rest - height) < Math.abs(nearest - height) ? rest : nearest,\n );\n}\n\n/** The heights a panel's sheet rests at in a viewer `viewerHeight` px tall: half of it, and nearly all. */\nexport function panelSheetHeightsOf(viewerHeight: number): readonly number[] {\n const tallest = Math.max(0, Math.round(viewerHeight - SHEET_TOP_CLEARANCE_PX));\n const open = Math.min(tallest, Math.round(viewerHeight * PANEL_SHEET_OPEN_FRACTION));\n return open < tallest ? [open, tallest] : [tallest];\n}\n","/**\n * A sheet: what a panel or a menu is on a phone. It slides up from the bottom\n * of the viewer, over the pages, in a layer over the whole viewer\n * (`viewer-layer.ts`); the viewer above it dims, and a tap there closes it.\n * Its handle drags it taller or shorter, or down to close it, and a flick\n * moves it a whole step (`sheet-rest.ts`). It keeps clear of the home bar and\n * the screen's rounded corners when the viewer reaches the screen's edge.\n * A sheet takes focus when it opens, keeps Tab inside it, closes on Escape\n * and gives focus back to the button that opened it; a menu's sheet leaves\n * the keyboard to its menu. A sheet that holds a list closes when one of its\n * items is picked ({@link useCloseOnPick}).\n */\nimport { computeReleaseVelocity, observeOutsidePress } from '@embedpdf/web';\nimport {\n createContext,\n useContext,\n useLayoutEffect,\n useRef,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\n\nimport { safeAreaPaddingOf } from './screen-edges';\nimport { SHEET_TOP_CLEARANCE_PX, panelSheetHeightsOf, sheetRestOf } from './sheet-rest';\nimport { MODAL_SELECTOR, POPOVER, attachViewerLayer, holdFocus } from './viewer-layer';\n\n/** A press that starts on one of these in the handle's row is the control's, not a drag. */\nconst CONTROL_SELECTOR =\n 'button, a[href], input, select, textarea, [role=\"tab\"], [contenteditable]:not([contenteditable=\"false\"])';\n\n/** The dimmed viewer behind a sheet or a dialog. */\nexport const SCRIM_CLASS = 'bg-black/30 transition-opacity duration-200 starting:opacity-0';\n\nconst NO_PICK = () => {};\n\nconst CloseOnPickContext = createContext<() => void>(NO_PICK);\n\n/** Gives what's inside a sheet or an overlay the close it runs when one of its items is picked. */\nexport const CloseOnPickProvider = CloseOnPickContext.Provider;\n\n/**\n * What a list's item runs when it's picked: it closes the sheet or the overlay the list is in,\n * so you see where it took you. It does nothing in a docked panel, or in one that isn't a list.\n */\nexport function useCloseOnPick(): () => void {\n return useContext(CloseOnPickContext);\n}\n\n/** Whether a press landed in another surface that holds focus, like a dialog opened over this one. */\nconst pressedInOtherModal = (event: PointerEvent, own: Element): boolean =>\n event\n .composedPath()\n .some((node) => node instanceof Element && node !== own && node.matches(MODAL_SELECTOR));\n\nexport interface SheetProps {\n /** Names the sheet for assistive technology. */\n readonly label: string;\n readonly onClose: () => void;\n /**\n * `'content'`: as tall as what's in it, like a menu. `'panel'`: opens at half the viewer's\n * height, and drags up to nearly all of it. Default `'content'`.\n */\n readonly size?: 'content' | 'panel';\n /** It holds a list: picking an item ({@link useCloseOnPick}) closes it. */\n readonly list?: boolean;\n /**\n * Whether it holds the keyboard (default true). A menu's sheet doesn't: its menu takes focus\n * and gives it back.\n */\n readonly trapFocus?: boolean;\n /** Drawn under the handle, above the part that scrolls; dragging it moves the sheet too. */\n readonly header?: ReactNode;\n /** The sheet's part name, for page CSS through `::part()`, when it is one: a panel's `panel`. */\n readonly part?: string;\n /** `data-*` attributes for the sheet, by their names without `data-`. */\n readonly data?: Readonly<Record<string, string>>;\n readonly children: ReactNode;\n}\n\ninterface Drag {\n readonly pointerId: number;\n readonly startY: number;\n readonly startHeight: number;\n /** The heights it can rest at, ascending. */\n readonly heights: readonly number[];\n readonly samples: { t: number; x: number; y: number }[];\n height: number;\n}\n\n/** `data` as the `data-*` attributes it names. */\nconst dataAttributesOf = (data: Readonly<Record<string, string>> | undefined) =>\n Object.fromEntries(Object.entries(data ?? {}).map(([name, value]) => [`data-${name}`, value]));\n\n/** How many pointer samples a drag keeps for its release speed. */\nconst DRAG_SAMPLES = 8;\n\nexport function Sheet({\n label,\n onClose,\n size = 'content',\n list = false,\n trapFocus = true,\n header,\n part,\n data,\n children,\n}: SheetProps) {\n const layer = useRef<HTMLDivElement>(null);\n const sheet = useRef<HTMLDivElement>(null);\n const close = useRef(onClose);\n close.current = onClose;\n /** Which of its heights a panel's sheet rests at: the first (open) or a taller one. */\n const restIndex = useRef(0);\n const drag = useRef<Drag | null>(null);\n\n /** The heights it rests at now: a panel's from the viewer's height, a menu's as tall as it is. */\n const heightsNow = (): readonly number[] =>\n size === 'panel'\n ? panelSheetHeightsOf(layer.current?.offsetHeight ?? 0)\n : [sheet.current?.offsetHeight ?? 0];\n\n /** Show the sheet dragged to `height` (its top that far above the viewer's bottom). */\n const show = (height: number, heights: readonly number[]) => {\n const element = sheet.current;\n if (!element || heights.length === 0) return;\n const lowest = heights[0]!;\n const tallest = heights[heights.length - 1]!;\n if (size === 'panel') element.style.height = `${Math.min(tallest, Math.max(lowest, height))}px`;\n const below = Math.max(0, lowest - height);\n element.style.translate = below > 0 ? `0 ${below}px` : '';\n };\n\n useLayoutEffect(() => {\n const layerElement = layer.current;\n const sheetElement = sheet.current;\n if (!layerElement || !sheetElement) return;\n const stopLayer = attachViewerLayer(layerElement, (edges) => {\n const padding = safeAreaPaddingOf(edges, ['right', 'bottom', 'left']);\n sheetElement.style.paddingLeft = padding.paddingLeft ?? '';\n sheetElement.style.paddingRight = padding.paddingRight ?? '';\n sheetElement.style.paddingBottom = padding.paddingBottom ?? '';\n sheetElement.style.maxHeight = `${Math.max(0, layerElement.offsetHeight - SHEET_TOP_CLEARANCE_PX)}px`;\n if (size === 'panel' && !drag.current) {\n const heights = panelSheetHeightsOf(layerElement.offsetHeight);\n show(heights[Math.min(restIndex.current, heights.length - 1)]!, heights);\n }\n });\n const held = trapFocus ? holdFocus(sheetElement, { onEscape: () => close.current() }) : null;\n // A press on the viewer above the sheet is the scrim's click; one outside the viewer closes it too.\n const stopOutside = observeOutsidePress(layerElement, (event) => {\n if (!pressedInOtherModal(event, sheetElement)) close.current();\n });\n return () => {\n stopOutside();\n held?.release();\n stopLayer();\n };\n // The sheet opens once; it closes by unmounting.\n }, []);\n\n const onGripDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.pointerType === 'mouse' && event.button !== 0) return;\n if ((event.target as Element).closest(CONTROL_SELECTOR)) return;\n const element = sheet.current;\n if (!element) return;\n event.currentTarget.setPointerCapture(event.pointerId);\n const startHeight = element.offsetHeight;\n drag.current = {\n pointerId: event.pointerId,\n startY: event.clientY,\n startHeight,\n heights: heightsNow(),\n samples: [{ t: event.timeStamp, x: event.clientX, y: event.clientY }],\n height: startHeight,\n };\n element.setAttribute('data-dragging', '');\n };\n\n const onGripMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n const current = drag.current;\n if (!current || current.pointerId !== event.pointerId) return;\n current.height = current.startHeight - (event.clientY - current.startY);\n current.samples.push({ t: event.timeStamp, x: event.clientX, y: event.clientY });\n if (current.samples.length > DRAG_SAMPLES) current.samples.shift();\n show(current.height, current.heights);\n };\n\n const onGripUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n const current = drag.current;\n if (!current || current.pointerId !== event.pointerId) return;\n drag.current = null;\n sheet.current?.removeAttribute('data-dragging');\n const cancelled = event.type === 'pointercancel';\n const velocity = cancelled\n ? 0\n : (computeReleaseVelocity(current.samples, event.timeStamp)?.vy ?? 0);\n const rest = cancelled\n ? current.heights[restIndex.current]!\n : sheetRestOf(current.heights, current.height, velocity);\n if (rest === null) {\n close.current();\n return;\n }\n restIndex.current = Math.max(0, current.heights.indexOf(rest));\n show(rest, current.heights);\n };\n\n return (\n <div\n ref={layer}\n {...POPOVER}\n data-epdf-layer=\"\"\n className=\"text-fg m-0 overflow-hidden border-0 bg-transparent p-0 open:flex open:flex-col\"\n style={{ position: 'fixed', inset: 'auto', maxWidth: 'none', maxHeight: 'none' }}\n >\n <div\n aria-hidden=\"true\"\n className={`min-h-0 flex-1 ${SCRIM_CLASS}`}\n onClick={() => close.current()}\n />\n <div\n ref={sheet}\n role={trapFocus ? 'dialog' : undefined}\n aria-modal={trapFocus ? true : undefined}\n aria-label={trapFocus ? label : undefined}\n part={part}\n {...dataAttributesOf(data)}\n data-epdf-sheet=\"\"\n className=\"border-border-subtle bg-elevated starting:translate-y-full data-dragging:transition-none relative flex w-full shrink-0 flex-col rounded-t-2xl border-t shadow-2xl transition-[translate,height] duration-200 ease-out motion-reduce:transition-none\"\n >\n <div\n className=\"shrink-0 touch-pan-x select-none\"\n onPointerDown={onGripDown}\n onPointerMove={onGripMove}\n onPointerUp={onGripUp}\n onPointerCancel={onGripUp}\n >\n <div\n data-epdf-sheet-handle=\"\"\n className=\"flex h-6 cursor-grab items-center justify-center active:cursor-grabbing\"\n >\n <span className=\"bg-border-strong h-1 w-10 rounded-full\" />\n </div>\n {header}\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden overscroll-contain\">\n <CloseOnPickProvider value={list ? () => close.current() : NO_PICK}>\n {children}\n </CloseOnPickProvider>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;AAiBA,MAAa,kBAA+B;CAC1C,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;AACR;;AAWA,MAAM,oBAAoB;;AAG1B,SAAgB,cACd,KACA,MACa;CACb,MAAM,SAAS,IAAI,QAAQ,KAAK,IAAI,OAAO,KAAK;CAChD,MAAM,OAAO,IAAI,SAAS,KAAK,IAAI,MAAM,KAAK;CAC9C,OAAO;EACL,KAAK,UAAU,IAAI,OAAO,qBAAqB,IAAI,SAAS;EAC5D,OAAO,QAAQ,IAAI,SAAS,KAAK,QAAQ,qBAAqB,IAAI,OAAO,KAAK;EAC9E,QAAQ,UAAU,IAAI,UAAU,KAAK,SAAS,qBAAqB,IAAI,MAAM,KAAK;EAClF,MAAM,QAAQ,IAAI,QAAQ,qBAAqB,IAAI,QAAQ;CAC7D;AACF;AAEA,MAAa,mBAAmB,MAAmB,UACjD,KAAK,QAAQ,MAAM,OACnB,KAAK,UAAU,MAAM,SACrB,KAAK,WAAW,MAAM,UACtB,KAAK,SAAS,MAAM;AAUtB,MAAM,UAAsE;CAC1E,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;AACR;;AAGA,SAAgB,kBACd,OACA,QAAwC;CAAC;CAAO;CAAS;CAAU;AAAM,GACxD;CACjB,MAAM,UAA2B,CAAC;CAClC,KAAK,MAAM,QAAQ,OACjB,IAAI,MAAM,OAAO,QAAQ,QAAQ,SAAS,uBAAuB,KAAK;CAExE,OAAO;AACT;;AAGA,SAAgB,aAAa,SAAqD;CAChF,MAAM,EAAE,aAAa,iBAAiB,QAAQ,cAAc;CAC5D,OAAO;EAAE,OAAO;EAAa,QAAQ;CAAa;AACpD;;;;;;;;;;;;;;ACnEA,MAAa,UAAU,EAAE,SAAS,SAAS;;AAG3C,MAAM,uBAAuB;;;;;AAS7B,MAAa,uBAAuB;;AAGpC,SAAS,WACP,SACA,KACM;CACN,QAAQ,MAAM,OAAO,GAAG,IAAI,KAAK;CACjC,QAAQ,MAAM,MAAM,GAAG,IAAI,IAAI;CAC/B,QAAQ,MAAM,QAAQ,GAAG,IAAI,MAAM;CACnC,QAAQ,MAAM,SAAS,GAAG,IAAI,OAAO;CAGrC,MAAM,SAAS,QAAQ,sBAAsB;CAC7C,IAAI,KAAK,IAAI,OAAO,OAAO,IAAI,IAAI,IAAI,MAAO,KAAK,IAAI,OAAO,MAAM,IAAI,GAAG,IAAI,IAAK;EAClF,QAAQ,MAAM,OAAO,GAAG,IAAI,IAAI,OAAO,OAAO,KAAK;EACnD,QAAQ,MAAM,MAAM,GAAG,IAAI,IAAI,MAAM,OAAO,IAAI;CAClD;AACF;;;;;;AAOA,SAAgB,kBACd,OACA,SACY;CACZ,MAAM,OAAO,MAAM,eAAe,QAAQ,oBAAoB,KAAK;CACnE,IAAI,OAAO,MAAM,gBAAgB,YAAY,MAAM,YAAY;CAC/D,IAAI,SAAS;CACb,MAAM,cAAc;EAClB,MAAM,OAAO,aAAa,KAAK;EAC/B,MAAM,OAAO,MAAM,sBAAsB,KAAK;GAC5C,MAAM;GACN,KAAK;GACL,OAAO,KAAK;GACZ,QAAQ,KAAK;EACf;EACA,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI;EAClC,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,GAAG;EAChC,MAAM,MAAM;GACV;GACA;GACA,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,OAAO,KAAK,KAAK,IAAI,IAAI;GAC1D,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,KAAK,MAAM,IAAI,GAAG;EAC9D;EAEA,MAAM,MAAM,GAAG,IAAI,KAAK,GAAG,IAAI,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,OAAO,GAAG,KAAK,MAAM,GAAG,KAAK;EACpF,IAAI,QAAQ,QAAQ;EACpB,SAAS;EACT,WAAW,OAAO,GAAG;EACrB,UAAU,cAAc,MAAM,IAAI,CAAC;CACrC;CACA,MAAM;CACN,MAAM,UAAU,IAAI,eAAe,KAAK;CACxC,IAAI,MAAM,QAAQ,QAAQ,IAAI;CAC9B,MAAM,eAAe,sBAAsB,KAAK;CAChD,aAAa;EACX,aAAa;EACb,QAAQ,WAAW;EACnB,IAAI,OAAO,MAAM,gBAAgB,cAAc,MAAM,QAAQ,eAAe,GAC1E,MAAM,YAAY;CAEtB;AACF;;;;;;;;;AAiBA,SAAgB,UACd,WACA,SAKW;CACX,MAAM,MAAM,UAAU;CACtB,MAAM,SAAS,oBAAoB,GAAG;CACtC,MAAM,aAAa,UAAyB;EAC1C,IAAI,MAAM,QAAQ,YAAY,MAAM,kBAAkB;EACtD,MAAM,eAAe;EAErB,MAAM,gBAAgB;EACtB,QAAQ,SAAS;CACnB;CACA,UAAU,iBAAiB,WAAW,SAAS;CAC/C,IAAI,cAAmC;CACvC,IAAI,QAAQ,SAAS,OACnB,cAAc,WAAW,QAAQ,YAAY;MAE7C,cAAc,gBAAgB,WAAW;EACvC,cAAc,QAAQ;EACtB,aAAa;CACf,CAAC;CAEH,MAAM,kBAAkB;EACtB,cAAc;EACd,cAAc;EACd,UAAU,oBAAoB,WAAW,SAAS;CACpD;CACA,OAAO;EACL;EACA,eAAe;GACb,UAAU;GACV,MAAM,SAAS,oBAAoB,GAAG;GACtC,MAAM,UACJ,WAAW,QAAQ,UAAU,SAAS,MAAM,KAAK,OAAO,aAAA,sBAAiC;GAC3F,IAAI,QAAQ,eAAe,SAAS,OAAO,MAAM;EACnD;CACF;AACF;;ACjJA,MAAa,4BAA4B;;;;;AASzC,SAAgB,YACd,SACA,QACA,UACe;CACf,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,IAAI,YAAA,KAAkC;EACpC,MAAM,QAAQ,QAAQ,QAAQ,SAAS,OAAO,SAAS,CAAC;EACxD,OAAO,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,KAAM;CACvD;CACA,IAAI,YAAY,MACd,OAAO,QAAQ,MAAM,SAAS,OAAO,SAAS,CAAC,KAAK,QAAQ,QAAQ,SAAS;CAE/E,IAAI,SAAS,QAAQ,KAAM,GAAG,OAAO;CACrC,OAAO,QAAQ,QAAQ,SAAS,SAC9B,KAAK,IAAI,OAAO,MAAM,IAAI,KAAK,IAAI,UAAU,MAAM,IAAI,OAAO,OAChE;AACF;;AAGA,SAAgB,oBAAoB,cAAyC;CAC3E,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,MAAM,eAAA,EAAqC,CAAC;CAC7E,MAAM,OAAO,KAAK,IAAI,SAAS,KAAK,MAAM,eAAe,yBAAyB,CAAC;CACnF,OAAO,OAAO,UAAU,CAAC,MAAM,OAAO,IAAI,CAAC,OAAO;AACpD;;;;;;;;;;;;;;;;AClBA,MAAM,mBACJ;;AAGF,MAAa,cAAc;AAE3B,MAAM,gBAAgB,CAAC;AAEvB,MAAM,qBAAqB,cAA0B,OAAO;;AAG5D,MAAa,sBAAsB,mBAAmB;;;;;AAMtD,SAAgB,iBAA6B;CAC3C,OAAO,WAAW,kBAAkB;AACtC;;AAGA,MAAM,uBAAuB,OAAqB,QAChD,MACG,aAAa,CAAC,CACd,MAAM,SAAS,gBAAgB,WAAW,SAAS,OAAO,KAAK,QAAA,uBAAsB,CAAC;;AAsC3F,MAAM,oBAAoB,SACxB,OAAO,YAAY,OAAO,QAAQ,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,QAAQ,QAAQ,KAAK,CAAC,CAAC;;AAG/F,MAAM,eAAe;AAErB,SAAgB,MAAM,EACpB,OACA,SACA,OAAO,WACP,OAAO,OACP,YAAY,MACZ,QACA,MACA,MACA,YACa;CACb,MAAM,QAAQ,OAAuB,IAAI;CACzC,MAAM,QAAQ,OAAuB,IAAI;CACzC,MAAM,QAAQ,OAAO,OAAO;CAC5B,MAAM,UAAU;;CAEhB,MAAM,YAAY,OAAO,CAAC;CAC1B,MAAM,OAAO,OAAoB,IAAI;;CAGrC,MAAM,mBACJ,SAAS,UACL,oBAAoB,MAAM,SAAS,gBAAgB,CAAC,IACpD,CAAC,MAAM,SAAS,gBAAgB,CAAC;;CAGvC,MAAM,QAAQ,QAAgB,YAA+B;EAC3D,MAAM,UAAU,MAAM;EACtB,IAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;EACtC,MAAM,SAAS,QAAQ;EACvB,MAAM,UAAU,QAAQ,QAAQ,SAAS;EACzC,IAAI,SAAS,SAAS,QAAQ,MAAM,SAAS,GAAG,KAAK,IAAI,SAAS,KAAK,IAAI,QAAQ,MAAM,CAAC,EAAE;EAC5F,MAAM,QAAQ,KAAK,IAAI,GAAG,SAAS,MAAM;EACzC,QAAQ,MAAM,YAAY,QAAQ,IAAI,KAAK,MAAM,MAAM;CACzD;CAEA,sBAAsB;EACpB,MAAM,eAAe,MAAM;EAC3B,MAAM,eAAe,MAAM;EAC3B,IAAI,CAAC,gBAAgB,CAAC,cAAc;EACpC,MAAM,YAAY,kBAAkB,eAAe,UAAU;GAC3D,MAAM,UAAU,kBAAkB,OAAO;IAAC;IAAS;IAAU;GAAM,CAAC;GACpE,aAAa,MAAM,cAAc,QAAQ,eAAe;GACxD,aAAa,MAAM,eAAe,QAAQ,gBAAgB;GAC1D,aAAa,MAAM,gBAAgB,QAAQ,iBAAiB;GAC5D,aAAa,MAAM,YAAY,GAAG,KAAK,IAAI,GAAG,aAAa,eAAA,EAAqC,EAAE;GAClG,IAAI,SAAS,WAAW,CAAC,KAAK,SAAS;IACrC,MAAM,UAAU,oBAAoB,aAAa,YAAY;IAC7D,KAAK,QAAQ,KAAK,IAAI,UAAU,SAAS,QAAQ,SAAS,CAAC,IAAK,OAAO;GACzE;EACF,CAAC;EACD,MAAM,OAAO,YAAY,UAAU,cAAc,EAAE,gBAAgB,MAAM,QAAQ,EAAE,CAAC,IAAI;EAExF,MAAM,cAAc,oBAAoB,eAAe,UAAU;GAC/D,IAAI,CAAC,oBAAoB,OAAO,YAAY,GAAG,MAAM,QAAQ;EAC/D,CAAC;EACD,aAAa;GACX,YAAY;GACZ,MAAM,QAAQ;GACd,UAAU;EACZ;CAEF,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,UAA6C;EAC/D,IAAI,MAAM,gBAAgB,WAAW,MAAM,WAAW,GAAG;EACzD,IAAK,MAAM,OAAmB,QAAQ,gBAAgB,GAAG;EACzD,MAAM,UAAU,MAAM;EACtB,IAAI,CAAC,SAAS;EACd,MAAM,cAAc,kBAAkB,MAAM,SAAS;EACrD,MAAM,cAAc,QAAQ;EAC5B,KAAK,UAAU;GACb,WAAW,MAAM;GACjB,QAAQ,MAAM;GACd;GACA,SAAS,WAAW;GACpB,SAAS,CAAC;IAAE,GAAG,MAAM;IAAW,GAAG,MAAM;IAAS,GAAG,MAAM;GAAQ,CAAC;GACpE,QAAQ;EACV;EACA,QAAQ,aAAa,iBAAiB,EAAE;CAC1C;CAEA,MAAM,cAAc,UAA6C;EAC/D,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,WAAW,QAAQ,cAAc,MAAM,WAAW;EACvD,QAAQ,SAAS,QAAQ,eAAe,MAAM,UAAU,QAAQ;EAChE,QAAQ,QAAQ,KAAK;GAAE,GAAG,MAAM;GAAW,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ,CAAC;EAC/E,IAAI,QAAQ,QAAQ,SAAS,cAAc,QAAQ,QAAQ,MAAM;EACjE,KAAK,QAAQ,QAAQ,QAAQ,OAAO;CACtC;CAEA,MAAM,YAAY,UAA6C;EAC7D,MAAM,UAAU,KAAK;EACrB,IAAI,CAAC,WAAW,QAAQ,cAAc,MAAM,WAAW;EACvD,KAAK,UAAU;EACf,MAAM,SAAS,gBAAgB,eAAe;EAC9C,MAAM,YAAY,MAAM,SAAS;EACjC,MAAM,WAAW,YACb,IACC,uBAAuB,QAAQ,SAAS,MAAM,SAAS,CAAC,EAAE,MAAM;EACrE,MAAM,OAAO,YACT,QAAQ,QAAQ,UAAU,WAC1B,YAAY,QAAQ,SAAS,QAAQ,QAAQ,QAAQ;EACzD,IAAI,SAAS,MAAM;GACjB,MAAM,QAAQ;GACd;EACF;EACA,UAAU,UAAU,KAAK,IAAI,GAAG,QAAQ,QAAQ,QAAQ,IAAI,CAAC;EAC7D,KAAK,MAAM,QAAQ,OAAO;CAC5B;CAEA,OACE,qBAAC,OAAD;EACE,KAAK;EACL,GAAI;EACJ,mBAAgB;EAChB,WAAU;EACV,OAAO;GAAE,UAAU;GAAS,OAAO;GAAQ,UAAU;GAAQ,WAAW;EAAO;EALjF,UAAA,CAOE,oBAAC,OAAD;GACE,eAAY;GACZ,WAAW,kBAAkB;GAC7B,eAAe,MAAM,QAAQ;EAC9B,CAAA,GACD,qBAAC,OAAD;GACE,KAAK;GACL,MAAM,YAAY,WAAW,KAAA;GAC7B,cAAY,YAAY,OAAO,KAAA;GAC/B,cAAY,YAAY,QAAQ,KAAA;GAC1B;GACN,GAAI,iBAAiB,IAAI;GACzB,mBAAgB;GAChB,WAAU;GARZ,UAAA,CAUE,qBAAC,OAAD;IACE,WAAU;IACV,eAAe;IACf,eAAe;IACf,aAAa;IACb,iBAAiB;IALnB,UAAA,CAOE,oBAAC,OAAD;KACE,0BAAuB;KACvB,WAAU;KAEV,UAAA,oBAAC,QAAD,EAAM,WAAU,yCAA0C,CAAA;IACvD,CAAA,GACJ,MACE;GACL,CAAA,GAAA,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,qBAAD;KAAqB,OAAO,aAAa,MAAM,QAAQ,IAAI;KACxD;IACkB,CAAA;GAClB,CAAA,CACF;EACF,CAAA,CAAA;;AAET"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signature-inspector-DyO313Qf.cjs","names":["FormToken","Icon","Anchored"],"sources":["../src/ui/signature-inspector.tsx"],"sourcesContent":["/**\n * The validation popover (`signature-inspector` surface): what a signed\n * field's signature says and whether it holds — the four independent facts\n * (integrity, cryptography, trust, changes since) and the signer's claims,\n * anchored at the widget when its box is known, plus the signed revision as\n * a download (the exact bytes the signature covers). Mounted in the Stage\n * overlay so `<Anchored>` can project onto the page.\n */\nimport { useEffect, useState } from 'react';\nimport { Anchored } from '@embedpdf/react/anchored';\nimport { FormToken } from '@embedpdf/react/form';\nimport { useOptionalCapability } from '@embedpdf/react/runtime';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useT } from '@embedpdf/react/i18n';\nimport {\n useSignature,\n useSignatureState,\n type FormFieldRef,\n type SignatureVerdict,\n} from '@embedpdf/react/signature';\nimport { Icon } from './icons';\n\nconst verdictKey = (verdict: SignatureVerdict | null): string =>\n !verdict\n ? 'demo.verdictIndeterminate'\n : verdict.summary === 'valid'\n ? 'demo.verdictValid'\n : verdict.summary === 'valid-untrusted'\n ? 'demo.verdictValidUntrusted'\n : verdict.summary === 'invalid'\n ? verdict.modifications.basis === 'working-copy'\n ? 'demo.verdictWillInvalidate'\n : 'demo.verdictInvalid'\n : 'demo.verdictIndeterminate';\n\n/** A PDF date string (`D:YYYYMMDDHHmmSSZ` or with a zone offset) as a locale date; the raw text when it is not one. */\n/** A moment in the reader's locale; the text itself if it isn't one. */\nconst dateTime = (iso: string): string => {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? iso : date.toLocaleString();\n};\n\nconst tone = (summary: SignatureVerdict['summary'] | null): string =>\n summary === 'valid'\n ? 'text-green-600'\n : summary === 'invalid'\n ? 'text-red-600'\n : summary === 'valid-untrusted'\n ? 'text-amber-600'\n : 'text-fg-muted';\n\nexport function SignatureInspector() {\n const t = useT();\n const surface = useSurface('signature-inspector');\n const signature = useSignature();\n // Re-render when the signatures are read, and when one or its verdict changes.\n const status = useSignatureState((state) => state.status);\n useSignatureState((state) => state.signatures);\n const [validating, setValidating] = useState(false);\n const field = surface.props?.field as FormFieldRef | undefined;\n const dto = field ? signature.getSignature(field) : null;\n const verdict = field ? signature.getVerdict(field) : null;\n const widget = dto?.widget ?? null;\n // Where the signature shows is its widget's row in the form.\n const form = useOptionalCapability(FormToken);\n const box = (widget && form?.getWidget(widget)?.rect) ?? null;\n\n // Open on a field never validated: judge it now.\n useEffect(() => {\n if (!surface.isOpen || !dto?.signed || signature.listVerdicts()) return;\n setValidating(true);\n void signature.validate().finally(() => setValidating(false));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [surface.isOpen, dto?.index]);\n\n if (!surface.isOpen || !field || !dto || status !== 'ready') return null;\n\n const revalidate = () => {\n setValidating(true);\n void signature.validate().finally(() => setValidating(false));\n };\n const summary = verdict?.summary ?? null;\n const modifications = verdict?.modifications.verdict ?? null;\n const row = (label: string, value: string, className = 'text-fg') => (\n <div className=\"flex items-baseline justify-between gap-3 text-xs\">\n <span className=\"text-fg-muted\">{label}</span>\n <span className={`text-end ${className}`}>{value}</span>\n </div>\n );\n\n const card = (\n <div className=\"border-border bg-elevated w-72 rounded-lg border p-3 text-sm shadow-xl\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-fg font-semibold\">{t('demo.inspectTitle')}</span>\n <button\n type=\"button\"\n onClick={surface.close}\n className=\"text-fg-muted hover:bg-hover grid h-6 w-6 place-items-center rounded\"\n aria-label={t('demo.cancel')}\n >\n <Icon name=\"x\" size={14} />\n </button>\n </div>\n <p className={`mt-1 text-sm font-medium ${tone(summary)}`}>\n {validating ? t('demo.signaturesValidating') : t(verdictKey(verdict))}\n </p>\n <div className=\"mt-2 flex flex-col gap-1\">\n {row(t('demo.inspectSigner'), dto.signer.name ?? '—')}\n {dto.signer.reason ? row(t('demo.inspectReason'), dto.signer.reason) : null}\n {dto.signer.location ? row(t('demo.inspectLocation'), dto.signer.location) : null}\n {dto.signer.signedAt ? row(t('demo.inspectTime'), dateTime(dto.signer.signedAt)) : null}\n </div>\n <div className=\"border-border-subtle mt-2 flex flex-col gap-1 border-t pt-2\">\n {row(\n t('demo.inspectIntegrity'),\n verdict?.integrity ?? '—',\n tone(\n verdict?.integrity === 'valid'\n ? 'valid'\n : verdict?.integrity === 'invalid'\n ? 'invalid'\n : null,\n ),\n )}\n {row(t('demo.inspectCryptography'), verdict?.cryptography ?? '—')}\n {row(t('demo.inspectTrust'), verdict?.trust ?? '—')}\n {row(\n t('demo.inspectChanges'),\n modifications === 'unchanged'\n ? verdict?.modifications.undone\n ? t('demo.verdictRestored')\n : t('demo.verdictUnchanged')\n : modifications === 'permitted'\n ? t('demo.verdictPermitted')\n : modifications === 'forbidden'\n ? t('demo.verdictForbidden')\n : '—',\n modifications === 'forbidden' ? 'text-red-600' : 'text-fg',\n )}\n {verdict?.modifications.laterRevisions\n ? row(t('demo.inspectLaterRevisions'), String(verdict.modifications.laterRevisions))\n : null}\n </div>\n <div className=\"mt-3 flex justify-end gap-2\">\n <button\n type=\"button\"\n disabled={validating}\n onClick={revalidate}\n className=\"border-border text-fg hover:bg-hover rounded-md border px-2 py-1 text-xs disabled:opacity-60\"\n >\n {t('demo.signaturesValidate')}\n </button>\n <DownloadRevision field={field} />\n </div>\n </div>\n );\n\n if (widget?.page && box) {\n return (\n <Anchored anchor={{ page: widget.page, bounds: box }} placement=\"bottom\" gap={8}>\n {card}\n </Anchored>\n );\n }\n return <div className=\"absolute end-4 top-4 z-40\">{card}</div>;\n}\n\n/** The signed revision — the exact bytes the signature covers — as a file. */\nfunction DownloadRevision({ field }: { field: FormFieldRef }) {\n const t = useT();\n const signature = useSignature();\n const dto = signature.getSignature(field);\n const [busy, setBusy] = useState(false);\n if (!dto || dto.revisionIndex === null) return null;\n const revisionIndex = dto.revisionIndex;\n const run = async () => {\n setBusy(true);\n try {\n const bytes = await signature.readRevision({ revisionIndex });\n const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `${dto.fieldName}-signed.pdf`;\n anchor.click();\n URL.revokeObjectURL(url);\n } catch (error) {\n console.error('[embedpdf] signed revision download failed:', error);\n } finally {\n setBusy(false);\n }\n };\n return (\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => void run()}\n className=\"border-border text-fg hover:bg-hover rounded-md border px-2 py-1 text-xs disabled:opacity-60\"\n >\n {t('demo.inspectDownload')}\n </button>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signature-inspector-okFz8do6.js","names":[],"sources":["../src/ui/signature-inspector.tsx"],"sourcesContent":["/**\n * The validation popover (`signature-inspector` surface): what a signed\n * field's signature says and whether it holds — the four independent facts\n * (integrity, cryptography, trust, changes since) and the signer's claims,\n * anchored at the widget when its box is known, plus the signed revision as\n * a download (the exact bytes the signature covers). Mounted in the Stage\n * overlay so `<Anchored>` can project onto the page.\n */\nimport { useEffect, useState } from 'react';\nimport { Anchored } from '@embedpdf/react/anchored';\nimport { FormToken } from '@embedpdf/react/form';\nimport { useOptionalCapability } from '@embedpdf/react/runtime';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useT } from '@embedpdf/react/i18n';\nimport {\n useSignature,\n useSignatureState,\n type FormFieldRef,\n type SignatureVerdict,\n} from '@embedpdf/react/signature';\nimport { Icon } from './icons';\n\nconst verdictKey = (verdict: SignatureVerdict | null): string =>\n !verdict\n ? 'demo.verdictIndeterminate'\n : verdict.summary === 'valid'\n ? 'demo.verdictValid'\n : verdict.summary === 'valid-untrusted'\n ? 'demo.verdictValidUntrusted'\n : verdict.summary === 'invalid'\n ? verdict.modifications.basis === 'working-copy'\n ? 'demo.verdictWillInvalidate'\n : 'demo.verdictInvalid'\n : 'demo.verdictIndeterminate';\n\n/** A PDF date string (`D:YYYYMMDDHHmmSSZ` or with a zone offset) as a locale date; the raw text when it is not one. */\n/** A moment in the reader's locale; the text itself if it isn't one. */\nconst dateTime = (iso: string): string => {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? iso : date.toLocaleString();\n};\n\nconst tone = (summary: SignatureVerdict['summary'] | null): string =>\n summary === 'valid'\n ? 'text-green-600'\n : summary === 'invalid'\n ? 'text-red-600'\n : summary === 'valid-untrusted'\n ? 'text-amber-600'\n : 'text-fg-muted';\n\nexport function SignatureInspector() {\n const t = useT();\n const surface = useSurface('signature-inspector');\n const signature = useSignature();\n // Re-render when the signatures are read, and when one or its verdict changes.\n const status = useSignatureState((state) => state.status);\n useSignatureState((state) => state.signatures);\n const [validating, setValidating] = useState(false);\n const field = surface.props?.field as FormFieldRef | undefined;\n const dto = field ? signature.getSignature(field) : null;\n const verdict = field ? signature.getVerdict(field) : null;\n const widget = dto?.widget ?? null;\n // Where the signature shows is its widget's row in the form.\n const form = useOptionalCapability(FormToken);\n const box = (widget && form?.getWidget(widget)?.rect) ?? null;\n\n // Open on a field never validated: judge it now.\n useEffect(() => {\n if (!surface.isOpen || !dto?.signed || signature.listVerdicts()) return;\n setValidating(true);\n void signature.validate().finally(() => setValidating(false));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [surface.isOpen, dto?.index]);\n\n if (!surface.isOpen || !field || !dto || status !== 'ready') return null;\n\n const revalidate = () => {\n setValidating(true);\n void signature.validate().finally(() => setValidating(false));\n };\n const summary = verdict?.summary ?? null;\n const modifications = verdict?.modifications.verdict ?? null;\n const row = (label: string, value: string, className = 'text-fg') => (\n <div className=\"flex items-baseline justify-between gap-3 text-xs\">\n <span className=\"text-fg-muted\">{label}</span>\n <span className={`text-end ${className}`}>{value}</span>\n </div>\n );\n\n const card = (\n <div className=\"border-border bg-elevated w-72 rounded-lg border p-3 text-sm shadow-xl\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-fg font-semibold\">{t('demo.inspectTitle')}</span>\n <button\n type=\"button\"\n onClick={surface.close}\n className=\"text-fg-muted hover:bg-hover grid h-6 w-6 place-items-center rounded\"\n aria-label={t('demo.cancel')}\n >\n <Icon name=\"x\" size={14} />\n </button>\n </div>\n <p className={`mt-1 text-sm font-medium ${tone(summary)}`}>\n {validating ? t('demo.signaturesValidating') : t(verdictKey(verdict))}\n </p>\n <div className=\"mt-2 flex flex-col gap-1\">\n {row(t('demo.inspectSigner'), dto.signer.name ?? '—')}\n {dto.signer.reason ? row(t('demo.inspectReason'), dto.signer.reason) : null}\n {dto.signer.location ? row(t('demo.inspectLocation'), dto.signer.location) : null}\n {dto.signer.signedAt ? row(t('demo.inspectTime'), dateTime(dto.signer.signedAt)) : null}\n </div>\n <div className=\"border-border-subtle mt-2 flex flex-col gap-1 border-t pt-2\">\n {row(\n t('demo.inspectIntegrity'),\n verdict?.integrity ?? '—',\n tone(\n verdict?.integrity === 'valid'\n ? 'valid'\n : verdict?.integrity === 'invalid'\n ? 'invalid'\n : null,\n ),\n )}\n {row(t('demo.inspectCryptography'), verdict?.cryptography ?? '—')}\n {row(t('demo.inspectTrust'), verdict?.trust ?? '—')}\n {row(\n t('demo.inspectChanges'),\n modifications === 'unchanged'\n ? verdict?.modifications.undone\n ? t('demo.verdictRestored')\n : t('demo.verdictUnchanged')\n : modifications === 'permitted'\n ? t('demo.verdictPermitted')\n : modifications === 'forbidden'\n ? t('demo.verdictForbidden')\n : '—',\n modifications === 'forbidden' ? 'text-red-600' : 'text-fg',\n )}\n {verdict?.modifications.laterRevisions\n ? row(t('demo.inspectLaterRevisions'), String(verdict.modifications.laterRevisions))\n : null}\n </div>\n <div className=\"mt-3 flex justify-end gap-2\">\n <button\n type=\"button\"\n disabled={validating}\n onClick={revalidate}\n className=\"border-border text-fg hover:bg-hover rounded-md border px-2 py-1 text-xs disabled:opacity-60\"\n >\n {t('demo.signaturesValidate')}\n </button>\n <DownloadRevision field={field} />\n </div>\n </div>\n );\n\n if (widget?.page && box) {\n return (\n <Anchored anchor={{ page: widget.page, bounds: box }} placement=\"bottom\" gap={8}>\n {card}\n </Anchored>\n );\n }\n return <div className=\"absolute end-4 top-4 z-40\">{card}</div>;\n}\n\n/** The signed revision — the exact bytes the signature covers — as a file. */\nfunction DownloadRevision({ field }: { field: FormFieldRef }) {\n const t = useT();\n const signature = useSignature();\n const dto = signature.getSignature(field);\n const [busy, setBusy] = useState(false);\n if (!dto || dto.revisionIndex === null) return null;\n const revisionIndex = dto.revisionIndex;\n const run = async () => {\n setBusy(true);\n try {\n const bytes = await signature.readRevision({ revisionIndex });\n const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `${dto.fieldName}-signed.pdf`;\n anchor.click();\n URL.revokeObjectURL(url);\n } catch (error) {\n console.error('[embedpdf] signed revision download failed:', error);\n } finally {\n setBusy(false);\n }\n };\n return (\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => void run()}\n className=\"border-border text-fg hover:bg-hover rounded-md border px-2 py-1 text-xs disabled:opacity-60\"\n >\n {t('demo.inspectDownload')}\n </button>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signatures-panel-B56PC6d9.cjs","names":["useSignatureSettings","restoreStampLibrariesOnce","Icon","SignatureToken"],"sources":["../src/ui/signatures-panel.tsx"],"sourcesContent":["/**\n * The signatures sidebar (right panel), a signature sheet like Preview's.\n * One row per person: a stamp library of kind `signatures` holding a\n * full signature and, optionally, initials. Nothing is stored beyond the\n * file; rename/export/delete are the library verbs.\n *\n * pick a mark → with a target field (\"sign here\" was clicked, or a\n * signature widget selected) the mark goes into that field by the\n * plugin's mode; otherwise it arms — hover a page for the ghost, click a\n * signature field to sign it, click anywhere else to drop it as a stamp.\n *\n * Below the people: the signature fields of this document, signed or not,\n * with their verdicts — click an unsigned one to target it, a signed one to\n * inspect it.\n */\nimport { useEffect, useState } from 'react';\nimport { useInteractionState } from '@embedpdf/react/interaction';\nimport { useSelector } from '@embedpdf/react/runtime';\nimport { useT } from '@embedpdf/react/i18n';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useStamp, useStampAssetPreviewUrl, type StampAsset } from '@embedpdf/react/stamp';\nimport {\n SignatureToken,\n useSignature,\n useSignatureState,\n useSignatureEvent,\n useSignerRows,\n type SignatureDTO,\n type SignatureVerdict,\n type SignerRow,\n} from '@embedpdf/react/signature';\nimport { useSignatureSettings } from '../config-context';\nimport { Icon } from './icons';\nimport { restoreStampLibrariesOnce } from './stamp-store';\n\nconst fieldLabel = (\n field: { kind: 'fqn'; name: string } | { kind: 'objectNumber'; objectNumber: number },\n): string => (field.kind === 'fqn' ? field.name : `#${field.objectNumber}`);\n\nexport function SignaturesPanel() {\n const t = useT();\n const stamp = useStamp();\n const signature = useSignature();\n const config = useSignatureSettings();\n const rows = useSignerRows();\n const target = useSignatureState((state) => state.target);\n const busy = useSignatureState((state) => state.busy);\n const { activeToolId } = useInteractionState();\n const maker = useSurface('signature-maker');\n const [armedId, setArmedId] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n // Acrobat's warning: an unsaved edit just turned a signature that held into\n // one a save would invalidate. Shown until the next verdicts land.\n const [invalidating, setInvalidating] = useState<string | null>(null);\n useSignatureEvent(\n (signature) => signature.onInvalidationPredicted,\n (event) =>\n setInvalidating(signature.getSignature(event.field)?.fieldName ?? fieldLabel(event.field)),\n );\n useSignatureEvent(\n (signature) => signature.onValidated,\n (event) => {\n if (\n !event.verdicts.some(\n (verdict) =>\n verdict.summary === 'invalid' && verdict.modifications.basis === 'working-copy',\n )\n )\n setInvalidating(null);\n },\n );\n\n // The people live in the same store as the stamps: bring them back on\n // first open (a no-op when the store component already did).\n useEffect(() => {\n void restoreStampLibrariesOnce(stamp);\n }, [stamp]);\n useEffect(() => {\n if (activeToolId !== 'stamp') setArmedId(null);\n }, [activeToolId]);\n\n const pick = (asset: StampAsset) => {\n setError(null);\n if (target) {\n void signature.placeMark({ assetId: asset.id }, { field: target }).catch((error) => {\n console.error('[embedpdf] placing the mark failed:', error);\n setError(t('demo.signError'));\n });\n return;\n }\n setArmedId(asset.id);\n void stamp.armAsset(asset.id).catch((error) => {\n console.error('[embedpdf] arm mark failed:', error);\n setArmedId(null);\n setError(t('demo.stampsArmError'));\n });\n };\n\n const canAddPerson = (config.libraries ?? 'many') === 'many' || rows.length === 0;\n const wantsInitials = (config.kinds ?? ['signature', 'initials']).includes('initials');\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"min-h-0 flex-1 overflow-y-auto p-3\">\n {rows.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-8 text-center\">\n <Icon name=\"signature\" size={32} className=\"text-fg-muted\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.signaturesEmpty')}</p>\n </div>\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {rows.map((row) => (\n <SignerRowView\n key={row.libraryId}\n row={row}\n armedId={armedId}\n wantsInitials={wantsInitials}\n onPick={pick}\n onAddInitials={() =>\n maker.open({ exclusive: 'modal', props: { libraryId: row.libraryId } })\n }\n />\n ))}\n </ul>\n )}\n <DocumentSignatures />\n </div>\n\n {invalidating && (\n <div className=\"border-border-subtle shrink-0 border-t px-3 py-2 text-xs text-amber-700\">\n {t('demo.signaturesInvalidating', { params: { field: invalidating } })}\n </div>\n )}\n {(error || target || armedId) && (\n <div\n className={`border-border-subtle shrink-0 border-t px-3 py-2 text-xs ${\n error ? 'text-red-600' : 'text-fg-muted'\n }`}\n >\n {error ??\n (target\n ? busy\n ? t('demo.signSigning')\n : t('demo.signaturesTargetHint')\n : t('demo.signaturesArmedHint'))}\n </div>\n )}\n\n {canAddPerson ? (\n <div className=\"border-border-subtle shrink-0 border-t p-3\">\n <button\n type=\"button\"\n onClick={() => maker.open({ exclusive: 'modal' })}\n className=\"border-border text-fg hover:bg-hover flex w-full items-center justify-center gap-2 rounded-md border px-3 py-1.5 text-sm\"\n >\n <Icon name=\"plus\" size={16} />\n {t('demo.signaturesNew')}\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction SignerRowView({\n row,\n armedId,\n wantsInitials,\n onPick,\n onAddInitials,\n}: {\n row: SignerRow;\n armedId: string | null;\n wantsInitials: boolean;\n onPick: (asset: StampAsset) => void;\n onAddInitials: () => void;\n}) {\n const t = useT();\n const stamp = useStamp();\n const [renaming, setRenaming] = useState<string | null>(null);\n\n const exportPdf = async () => {\n const bytes = await stamp.exportLibrary(row.libraryId).catch(() => null);\n if (!bytes) return;\n const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `${row.name || 'signature'}.pdf`;\n anchor.click();\n URL.revokeObjectURL(url);\n };\n const commitRename = () => {\n const name = renaming?.trim();\n setRenaming(null);\n if (name && name !== row.name) void stamp.updateLibrary(row.libraryId, { name });\n };\n const iconButton = 'text-fg-muted hover:text-fg grid h-6 w-6 shrink-0 place-items-center rounded';\n\n return (\n <li className=\"border-border-subtle rounded-md border p-2\">\n <div className=\"flex items-center gap-1\">\n {renaming !== null ? (\n <input\n autoFocus\n value={renaming}\n onChange={(event) => setRenaming(event.target.value)}\n onBlur={commitRename}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commitRename();\n if (event.key === 'Escape') setRenaming(null);\n }}\n className=\"border-border bg-surface text-fg min-w-0 flex-1 rounded border px-1.5 py-0.5 text-sm\"\n />\n ) : (\n <span className=\"text-fg min-w-0 flex-1 truncate text-sm font-medium\">{row.name}</span>\n )}\n <button\n type=\"button\"\n onClick={() => setRenaming(row.name)}\n title={t('demo.signaturesRename')}\n className={iconButton}\n >\n <Icon name=\"pencilMarker\" size={13} />\n </button>\n <button\n type=\"button\"\n onClick={exportPdf}\n title={t('demo.signaturesExport')}\n className={iconButton}\n >\n <Icon name=\"download\" size={13} />\n </button>\n <button\n type=\"button\"\n onClick={() => void stamp.deleteLibrary(row.libraryId)}\n title={t('demo.signaturesRemove')}\n className={iconButton}\n >\n <Icon name=\"trash\" size={13} />\n </button>\n </div>\n <div className=\"mt-2 grid grid-cols-[2fr_1fr] gap-2\">\n {row.signatures.map((asset) => (\n <MarkThumb\n key={asset.id}\n asset={asset}\n label={t('demo.signatureLabel')}\n armed={armedId === asset.id}\n onPick={() => onPick(asset)}\n />\n ))}\n {wantsInitials ? (\n row.initials ? (\n <MarkThumb\n asset={row.initials}\n label={t('demo.initialsLabel')}\n armed={armedId === row.initials.id}\n onPick={() => onPick(row.initials!)}\n />\n ) : (\n <button\n type=\"button\"\n onClick={onAddInitials}\n title={t('demo.signaturesAddInitials')}\n className=\"border-border-subtle text-fg-muted hover:bg-hover flex h-16 items-center justify-center rounded-md border border-dashed text-xs\"\n >\n <Icon name=\"plus\" size={14} />\n </button>\n )\n ) : null}\n </div>\n </li>\n );\n}\n\nfunction MarkThumb({\n asset,\n label,\n armed,\n onPick,\n}: {\n asset: StampAsset;\n label: string;\n armed: boolean;\n onPick: () => void;\n}) {\n const url = useStampAssetPreviewUrl(asset.id);\n return (\n <button\n type=\"button\"\n onClick={onPick}\n title={label}\n aria-pressed={armed}\n className={`flex h-16 items-center justify-center rounded-md border p-1 ${\n armed\n ? 'border-accent bg-accent-light ring-accent ring-2'\n : 'border-border-subtle hover:border-border hover:bg-hover'\n }`}\n >\n {url ? (\n <img src={url} alt={label} className=\"max-h-full max-w-full object-contain\" />\n ) : (\n <span className=\"text-fg-muted text-xs\">{label}</span>\n )}\n </button>\n );\n}\n\n/** The signature fields of this document, with their state. */\nfunction DocumentSignatures() {\n const t = useT();\n const signature = useSignature();\n // Every signature field, signed or not; the signed ones carry their verdict in the state.\n const snapshot = useSelector(SignatureToken, (capability) => capability.getSnapshot());\n const signed = useSignatureState((state) => state.signatures);\n const target = useSignatureState((state) => state.target);\n const [validating, setValidating] = useState(false);\n const fields = snapshot?.signatures ?? [];\n const verdictOf = (dto: SignatureDTO) =>\n signed.find((entry) => entry.index === dto.index)?.verdict ?? null;\n // Three honest states: valid; valid on disk but unsaved edits would\n // invalidate it (the verdict judged the working copy); invalid on disk.\n const verdictLabel = (verdict: SignatureVerdict | null): string =>\n !verdict\n ? t('demo.signaturesSigned')\n : verdict.summary === 'valid'\n ? t('demo.verdictValid')\n : verdict.summary === 'valid-untrusted'\n ? t('demo.verdictValidUntrusted')\n : verdict.summary === 'indeterminate'\n ? t('demo.verdictIndeterminate')\n : verdict.modifications.basis === 'working-copy'\n ? t('demo.verdictWillInvalidate')\n : t('demo.verdictInvalid');\n const verdictTone = (verdict: SignatureVerdict | null): string =>\n !verdict || verdict.summary === 'indeterminate'\n ? 'text-fg-muted'\n : verdict.summary === 'invalid'\n ? verdict.modifications.basis === 'working-copy'\n ? 'text-amber-600'\n : 'text-red-600'\n : verdict.summary === 'valid-untrusted'\n ? 'text-amber-600'\n : 'text-green-600';\n const isTarget = (dto: SignatureDTO) =>\n !!target &&\n (target.kind === 'fqn'\n ? target.name === dto.fieldName\n : target.objectNumber === (dto.field.kind === 'objectNumber' ? dto.field.objectNumber : -1));\n const validate = () => {\n setValidating(true);\n void signature.validate().finally(() => setValidating(false));\n };\n\n return (\n <div className=\"mt-4\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-fg-muted text-xs font-semibold uppercase tracking-wide\">\n {t('demo.signaturesInDocument')}\n </span>\n {fields.some((signature) => signature.signed) ? (\n <button\n type=\"button\"\n disabled={validating}\n onClick={validate}\n className=\"text-accent text-xs hover:underline disabled:opacity-60\"\n >\n {validating ? t('demo.signaturesValidating') : t('demo.signaturesValidate')}\n </button>\n ) : null}\n </div>\n {fields.length === 0 ? (\n <p className=\"text-fg-muted mt-1 text-xs\">{t('demo.signaturesNone')}</p>\n ) : (\n <ul className=\"mt-1 flex flex-col gap-1\">\n {fields.map((dto) => {\n const verdict = verdictOf(dto);\n return (\n <li key={dto.index}>\n <button\n type=\"button\"\n onClick={() =>\n dto.signed\n ? signature.requestInspection(dto.field)\n : signature.setTarget(dto.field)\n }\n className={`hover:bg-hover flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-start text-sm ${\n isTarget(dto) ? 'bg-accent-light' : ''\n }`}\n >\n <Icon\n name={dto.signed ? 'check' : 'signature'}\n size={14}\n className={dto.signed ? 'text-green-600' : 'text-fg-muted'}\n />\n <span className=\"text-fg min-w-0 flex-1 truncate\">{dto.fieldName}</span>\n <span\n className={`shrink-0 text-end text-xs ${dto.signed ? verdictTone(verdict) : 'text-fg-muted'}`}\n >\n {dto.signed ? verdictLabel(verdict) : t('demo.signaturesUnsigned')}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signatures-panel-CgnFfhFm.js","names":[],"sources":["../src/ui/signatures-panel.tsx"],"sourcesContent":["/**\n * The signatures sidebar (right panel), a signature sheet like Preview's.\n * One row per person: a stamp library of kind `signatures` holding a\n * full signature and, optionally, initials. Nothing is stored beyond the\n * file; rename/export/delete are the library verbs.\n *\n * pick a mark → with a target field (\"sign here\" was clicked, or a\n * signature widget selected) the mark goes into that field by the\n * plugin's mode; otherwise it arms — hover a page for the ghost, click a\n * signature field to sign it, click anywhere else to drop it as a stamp.\n *\n * Below the people: the signature fields of this document, signed or not,\n * with their verdicts — click an unsigned one to target it, a signed one to\n * inspect it.\n */\nimport { useEffect, useState } from 'react';\nimport { useInteractionState } from '@embedpdf/react/interaction';\nimport { useSelector } from '@embedpdf/react/runtime';\nimport { useT } from '@embedpdf/react/i18n';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useStamp, useStampAssetPreviewUrl, type StampAsset } from '@embedpdf/react/stamp';\nimport {\n SignatureToken,\n useSignature,\n useSignatureState,\n useSignatureEvent,\n useSignerRows,\n type SignatureDTO,\n type SignatureVerdict,\n type SignerRow,\n} from '@embedpdf/react/signature';\nimport { useSignatureSettings } from '../config-context';\nimport { Icon } from './icons';\nimport { restoreStampLibrariesOnce } from './stamp-store';\n\nconst fieldLabel = (\n field: { kind: 'fqn'; name: string } | { kind: 'objectNumber'; objectNumber: number },\n): string => (field.kind === 'fqn' ? field.name : `#${field.objectNumber}`);\n\nexport function SignaturesPanel() {\n const t = useT();\n const stamp = useStamp();\n const signature = useSignature();\n const config = useSignatureSettings();\n const rows = useSignerRows();\n const target = useSignatureState((state) => state.target);\n const busy = useSignatureState((state) => state.busy);\n const { activeToolId } = useInteractionState();\n const maker = useSurface('signature-maker');\n const [armedId, setArmedId] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n // Acrobat's warning: an unsaved edit just turned a signature that held into\n // one a save would invalidate. Shown until the next verdicts land.\n const [invalidating, setInvalidating] = useState<string | null>(null);\n useSignatureEvent(\n (signature) => signature.onInvalidationPredicted,\n (event) =>\n setInvalidating(signature.getSignature(event.field)?.fieldName ?? fieldLabel(event.field)),\n );\n useSignatureEvent(\n (signature) => signature.onValidated,\n (event) => {\n if (\n !event.verdicts.some(\n (verdict) =>\n verdict.summary === 'invalid' && verdict.modifications.basis === 'working-copy',\n )\n )\n setInvalidating(null);\n },\n );\n\n // The people live in the same store as the stamps: bring them back on\n // first open (a no-op when the store component already did).\n useEffect(() => {\n void restoreStampLibrariesOnce(stamp);\n }, [stamp]);\n useEffect(() => {\n if (activeToolId !== 'stamp') setArmedId(null);\n }, [activeToolId]);\n\n const pick = (asset: StampAsset) => {\n setError(null);\n if (target) {\n void signature.placeMark({ assetId: asset.id }, { field: target }).catch((error) => {\n console.error('[embedpdf] placing the mark failed:', error);\n setError(t('demo.signError'));\n });\n return;\n }\n setArmedId(asset.id);\n void stamp.armAsset(asset.id).catch((error) => {\n console.error('[embedpdf] arm mark failed:', error);\n setArmedId(null);\n setError(t('demo.stampsArmError'));\n });\n };\n\n const canAddPerson = (config.libraries ?? 'many') === 'many' || rows.length === 0;\n const wantsInitials = (config.kinds ?? ['signature', 'initials']).includes('initials');\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"min-h-0 flex-1 overflow-y-auto p-3\">\n {rows.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-8 text-center\">\n <Icon name=\"signature\" size={32} className=\"text-fg-muted\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.signaturesEmpty')}</p>\n </div>\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {rows.map((row) => (\n <SignerRowView\n key={row.libraryId}\n row={row}\n armedId={armedId}\n wantsInitials={wantsInitials}\n onPick={pick}\n onAddInitials={() =>\n maker.open({ exclusive: 'modal', props: { libraryId: row.libraryId } })\n }\n />\n ))}\n </ul>\n )}\n <DocumentSignatures />\n </div>\n\n {invalidating && (\n <div className=\"border-border-subtle shrink-0 border-t px-3 py-2 text-xs text-amber-700\">\n {t('demo.signaturesInvalidating', { params: { field: invalidating } })}\n </div>\n )}\n {(error || target || armedId) && (\n <div\n className={`border-border-subtle shrink-0 border-t px-3 py-2 text-xs ${\n error ? 'text-red-600' : 'text-fg-muted'\n }`}\n >\n {error ??\n (target\n ? busy\n ? t('demo.signSigning')\n : t('demo.signaturesTargetHint')\n : t('demo.signaturesArmedHint'))}\n </div>\n )}\n\n {canAddPerson ? (\n <div className=\"border-border-subtle shrink-0 border-t p-3\">\n <button\n type=\"button\"\n onClick={() => maker.open({ exclusive: 'modal' })}\n className=\"border-border text-fg hover:bg-hover flex w-full items-center justify-center gap-2 rounded-md border px-3 py-1.5 text-sm\"\n >\n <Icon name=\"plus\" size={16} />\n {t('demo.signaturesNew')}\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction SignerRowView({\n row,\n armedId,\n wantsInitials,\n onPick,\n onAddInitials,\n}: {\n row: SignerRow;\n armedId: string | null;\n wantsInitials: boolean;\n onPick: (asset: StampAsset) => void;\n onAddInitials: () => void;\n}) {\n const t = useT();\n const stamp = useStamp();\n const [renaming, setRenaming] = useState<string | null>(null);\n\n const exportPdf = async () => {\n const bytes = await stamp.exportLibrary(row.libraryId).catch(() => null);\n if (!bytes) return;\n const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `${row.name || 'signature'}.pdf`;\n anchor.click();\n URL.revokeObjectURL(url);\n };\n const commitRename = () => {\n const name = renaming?.trim();\n setRenaming(null);\n if (name && name !== row.name) void stamp.updateLibrary(row.libraryId, { name });\n };\n const iconButton = 'text-fg-muted hover:text-fg grid h-6 w-6 shrink-0 place-items-center rounded';\n\n return (\n <li className=\"border-border-subtle rounded-md border p-2\">\n <div className=\"flex items-center gap-1\">\n {renaming !== null ? (\n <input\n autoFocus\n value={renaming}\n onChange={(event) => setRenaming(event.target.value)}\n onBlur={commitRename}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commitRename();\n if (event.key === 'Escape') setRenaming(null);\n }}\n className=\"border-border bg-surface text-fg min-w-0 flex-1 rounded border px-1.5 py-0.5 text-sm\"\n />\n ) : (\n <span className=\"text-fg min-w-0 flex-1 truncate text-sm font-medium\">{row.name}</span>\n )}\n <button\n type=\"button\"\n onClick={() => setRenaming(row.name)}\n title={t('demo.signaturesRename')}\n className={iconButton}\n >\n <Icon name=\"pencilMarker\" size={13} />\n </button>\n <button\n type=\"button\"\n onClick={exportPdf}\n title={t('demo.signaturesExport')}\n className={iconButton}\n >\n <Icon name=\"download\" size={13} />\n </button>\n <button\n type=\"button\"\n onClick={() => void stamp.deleteLibrary(row.libraryId)}\n title={t('demo.signaturesRemove')}\n className={iconButton}\n >\n <Icon name=\"trash\" size={13} />\n </button>\n </div>\n <div className=\"mt-2 grid grid-cols-[2fr_1fr] gap-2\">\n {row.signatures.map((asset) => (\n <MarkThumb\n key={asset.id}\n asset={asset}\n label={t('demo.signatureLabel')}\n armed={armedId === asset.id}\n onPick={() => onPick(asset)}\n />\n ))}\n {wantsInitials ? (\n row.initials ? (\n <MarkThumb\n asset={row.initials}\n label={t('demo.initialsLabel')}\n armed={armedId === row.initials.id}\n onPick={() => onPick(row.initials!)}\n />\n ) : (\n <button\n type=\"button\"\n onClick={onAddInitials}\n title={t('demo.signaturesAddInitials')}\n className=\"border-border-subtle text-fg-muted hover:bg-hover flex h-16 items-center justify-center rounded-md border border-dashed text-xs\"\n >\n <Icon name=\"plus\" size={14} />\n </button>\n )\n ) : null}\n </div>\n </li>\n );\n}\n\nfunction MarkThumb({\n asset,\n label,\n armed,\n onPick,\n}: {\n asset: StampAsset;\n label: string;\n armed: boolean;\n onPick: () => void;\n}) {\n const url = useStampAssetPreviewUrl(asset.id);\n return (\n <button\n type=\"button\"\n onClick={onPick}\n title={label}\n aria-pressed={armed}\n className={`flex h-16 items-center justify-center rounded-md border p-1 ${\n armed\n ? 'border-accent bg-accent-light ring-accent ring-2'\n : 'border-border-subtle hover:border-border hover:bg-hover'\n }`}\n >\n {url ? (\n <img src={url} alt={label} className=\"max-h-full max-w-full object-contain\" />\n ) : (\n <span className=\"text-fg-muted text-xs\">{label}</span>\n )}\n </button>\n );\n}\n\n/** The signature fields of this document, with their state. */\nfunction DocumentSignatures() {\n const t = useT();\n const signature = useSignature();\n // Every signature field, signed or not; the signed ones carry their verdict in the state.\n const snapshot = useSelector(SignatureToken, (capability) => capability.getSnapshot());\n const signed = useSignatureState((state) => state.signatures);\n const target = useSignatureState((state) => state.target);\n const [validating, setValidating] = useState(false);\n const fields = snapshot?.signatures ?? [];\n const verdictOf = (dto: SignatureDTO) =>\n signed.find((entry) => entry.index === dto.index)?.verdict ?? null;\n // Three honest states: valid; valid on disk but unsaved edits would\n // invalidate it (the verdict judged the working copy); invalid on disk.\n const verdictLabel = (verdict: SignatureVerdict | null): string =>\n !verdict\n ? t('demo.signaturesSigned')\n : verdict.summary === 'valid'\n ? t('demo.verdictValid')\n : verdict.summary === 'valid-untrusted'\n ? t('demo.verdictValidUntrusted')\n : verdict.summary === 'indeterminate'\n ? t('demo.verdictIndeterminate')\n : verdict.modifications.basis === 'working-copy'\n ? t('demo.verdictWillInvalidate')\n : t('demo.verdictInvalid');\n const verdictTone = (verdict: SignatureVerdict | null): string =>\n !verdict || verdict.summary === 'indeterminate'\n ? 'text-fg-muted'\n : verdict.summary === 'invalid'\n ? verdict.modifications.basis === 'working-copy'\n ? 'text-amber-600'\n : 'text-red-600'\n : verdict.summary === 'valid-untrusted'\n ? 'text-amber-600'\n : 'text-green-600';\n const isTarget = (dto: SignatureDTO) =>\n !!target &&\n (target.kind === 'fqn'\n ? target.name === dto.fieldName\n : target.objectNumber === (dto.field.kind === 'objectNumber' ? dto.field.objectNumber : -1));\n const validate = () => {\n setValidating(true);\n void signature.validate().finally(() => setValidating(false));\n };\n\n return (\n <div className=\"mt-4\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-fg-muted text-xs font-semibold uppercase tracking-wide\">\n {t('demo.signaturesInDocument')}\n </span>\n {fields.some((signature) => signature.signed) ? (\n <button\n type=\"button\"\n disabled={validating}\n onClick={validate}\n className=\"text-accent text-xs hover:underline disabled:opacity-60\"\n >\n {validating ? t('demo.signaturesValidating') : t('demo.signaturesValidate')}\n </button>\n ) : null}\n </div>\n {fields.length === 0 ? (\n <p className=\"text-fg-muted mt-1 text-xs\">{t('demo.signaturesNone')}</p>\n ) : (\n <ul className=\"mt-1 flex flex-col gap-1\">\n {fields.map((dto) => {\n const verdict = verdictOf(dto);\n return (\n <li key={dto.index}>\n <button\n type=\"button\"\n onClick={() =>\n dto.signed\n ? signature.requestInspection(dto.field)\n : signature.setTarget(dto.field)\n }\n className={`hover:bg-hover flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-start text-sm ${\n isTarget(dto) ? 'bg-accent-light' : ''\n }`}\n >\n <Icon\n name={dto.signed ? 'check' : 'signature'}\n size={14}\n className={dto.signed ? 'text-green-600' : 'text-fg-muted'}\n />\n <span className=\"text-fg min-w-0 flex-1 truncate\">{dto.fieldName}</span>\n <span\n className={`shrink-0 text-end text-xs ${dto.signed ? verdictTone(verdict) : 'text-fg-muted'}`}\n >\n {dto.signed ? verdictLabel(verdict) : t('demo.signaturesUnsigned')}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stamps-panel-B9NYGayn.cjs","names":["useStampSettings","ensureDefaultLibrary","resolveStampsLocale","DEFAULT_LIBRARY_ID","Icon"],"sources":["../src/ui/stamps-panel.tsx"],"sourcesContent":["/**\n * The stamps sidebar (right panel). The stamp plugin owns the libraries, the\n * asset bytes and the cached previews; this panel is the picker over them:\n *\n * a library <select> (\"All stamps\" + one per library, shown once there\n * are two) → a two-column grid of thumbnails → click a stamp → `armAsset`\n * arms the annotation plugin's stamp tool → hovering a page ghosts the\n * exact placement → each click on a page places one.\n *\n * Deliberately not a file dialog: picking arbitrary image bytes is the Image\n * tool's job (a click-then-pick tool, `tool:image`). The stamp button\n * opens a library; a library is a set of reusable, named assets — the two\n * gestures are different, so they are different controls.\n *\n * The panel stays open while you place, so a stamp can be dropped on several\n * pages and swapped without a round trip through the toolbar. A command can\n * open it on a library (`annotation:stamp-from-selection` → \"My stamps\")\n * through the surface's open props.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { useInteractionState } from '@embedpdf/react/interaction';\nimport {\n useStamp,\n useStampAssetPreviewUrl,\n useStampAssets,\n useStampLibraries,\n type StampAsset,\n} from '@embedpdf/react/stamp';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useI18nState, useT } from '@embedpdf/react/i18n';\nimport { useStampSettings } from '../config-context';\nimport {\n DEFAULT_LIBRARY_ID,\n ensureDefaultLibrary,\n resolveStampsLocale,\n} from '../config/default-stamps';\nimport { Icon } from './icons';\nimport { restoreStampLibrariesOnce } from './stamp-store';\n\nconst ALL = 'all';\n\nexport function StampsPanel() {\n const t = useT();\n const stamp = useStamp();\n const { standard, sidebar } = useStampSettings();\n // Which catalogs this sidebar shows (`plugins.stamp.sidebar`): the plain stamps by\n // default — never the people's marks, which have their own panel.\n const libraries = useStampLibraries({ kind: sidebar ?? ['stamps'] });\n const assets = useStampAssets();\n const { activeToolId } = useInteractionState();\n const { locale } = useI18nState();\n const surface = useSurface('stamps');\n const fileRef = useRef<HTMLInputElement>(null);\n const [armedId, setArmedId] = useState<string | null>(null);\n const [busy, setBusy] = useState<'loading' | 'importing' | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [picked, setPicked] = useState<string>(ALL);\n\n // A command opened the panel on a library (the surface's `libraryId` prop).\n const openedOn = surface.props?.libraryId;\n useEffect(() => {\n if (typeof openedOn === 'string') setPicked(openedOn);\n }, [openedOn]);\n\n // First open: the user's stored libraries (the workspace store restores\n // them; this only awaits it), then the built-in library for this locale —\n // never at viewer boot, so a viewer whose user never opens this panel pays\n // nothing for it. A locale change while open swaps the built-in library;\n // the user's own are untouched.\n useEffect(() => {\n let live = true;\n setBusy('loading');\n restoreStampLibrariesOnce(stamp)\n .then(() => ensureDefaultLibrary(stamp, resolveStampsLocale(locale), standard))\n .catch((error: unknown) => {\n console.error('[embedpdf] default stamps failed:', error);\n if (live) setError(t('demo.stampsError'));\n })\n .finally(() => live && setBusy(null));\n return () => {\n live = false;\n };\n // `t` and `standard` are init-stable; only the locale re-runs this.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stamp, locale]);\n\n // The interaction hub owns tool state: leaving the stamp tool (picking\n // another tool, pressing Escape) un-highlights the gallery.\n useEffect(() => {\n if (activeToolId !== 'stamp') setArmedId(null);\n }, [activeToolId]);\n\n const arm = (asset: StampAsset) => {\n setError(null);\n setArmedId(asset.id);\n void stamp.armAsset(asset.id).catch((error) => {\n console.error('[embedpdf] arm stamp failed:', error);\n setArmedId(null);\n setError(t('demo.stampsArmError'));\n });\n };\n\n const importPdf = (file: File) => {\n setError(null);\n setBusy('importing');\n // The file name is only a fallback: an Acrobat-authored or previously\n // exported library names itself through its /Title.\n stamp\n .importLibrary(file, { name: file.name.replace(/\\.pdf$/i, '') })\n .then(({ library }) => setPicked(library.id))\n .catch((error) => {\n console.error('[embedpdf] stamp library import failed:', error);\n setError(t('demo.stampsImportError'));\n })\n .finally(() => setBusy(null));\n };\n\n /** The library as the PDF it is — title, registry, artwork — for Acrobat\n * or another viewer. */\n const exportPdf = async (libraryId: string, name: string) => {\n const bytes = await stamp.exportLibrary(libraryId).catch(() => null);\n if (!bytes) return;\n const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `${name || 'stamps'}.pdf`;\n anchor.click();\n URL.revokeObjectURL(url);\n };\n\n // A removed library falls back to \"All\"; the picker never names a ghost.\n // One library needs no picker: it is simply the selection (so its export\n // button is reachable).\n const selectedId =\n libraries.length === 1\n ? libraries[0].id\n : libraries.some((library) => library.id === picked)\n ? picked\n : ALL;\n const selected =\n selectedId === ALL ? null : (libraries.find((library) => library.id === selectedId) ?? null);\n const shown =\n selectedId === ALL ? assets : assets.filter((asset) => asset.libraryId === selectedId);\n const isDefault = (libraryId: string) => libraryId === DEFAULT_LIBRARY_ID;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n {libraries.length > 0 && (\n <div className=\"border-border-subtle flex items-center gap-1 border-b p-2\">\n {libraries.length > 1 ? (\n <select\n value={selectedId}\n onChange={(event) => setPicked(event.target.value)}\n aria-label={t('panels.stamps')}\n className=\"border-border bg-surface text-fg min-w-0 flex-1 rounded border px-2 py-1.5 text-sm\"\n >\n <option value={ALL}>{t('demo.stampsAll')}</option>\n {libraries.map((library) => (\n <option key={library.id} value={library.id}>\n {library.name}\n </option>\n ))}\n </select>\n ) : (\n <span className=\"text-fg-muted min-w-0 flex-1 truncate px-1 text-xs font-semibold uppercase tracking-wide\">\n {libraries[0].name}\n </span>\n )}\n {selected && (\n <>\n <button\n type=\"button\"\n onClick={() => exportPdf(selected.id, selected.name)}\n title={t('demo.stampsExportLibrary')}\n className=\"text-fg-muted hover:text-fg grid h-7 w-7 shrink-0 place-items-center rounded\"\n >\n <Icon name=\"download\" size={14} />\n </button>\n {!isDefault(selected.id) && (\n <button\n type=\"button\"\n onClick={() => void stamp.deleteLibrary(selected.id)}\n title={t('demo.stampsRemoveLibrary')}\n className=\"text-fg-muted hover:text-fg grid h-7 w-7 shrink-0 place-items-center rounded\"\n >\n <Icon name=\"trash\" size={14} />\n </button>\n )}\n </>\n )}\n </div>\n )}\n\n <div className=\"min-h-0 flex-1 overflow-y-auto p-3\">\n {busy === 'loading' && shown.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-10 text-center\">\n <div className=\"border-border-subtle border-t-accent h-6 w-6 animate-spin rounded-full border-2\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.stampsLoading')}</p>\n </div>\n ) : shown.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-10 text-center\">\n <Icon name=\"rubberStamp\" size={32} className=\"text-fg-muted\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.stampsEmpty')}</p>\n </div>\n ) : (\n <ul className=\"grid grid-cols-2 gap-3\">\n {shown.map((asset) => (\n <li key={asset.id} className=\"group relative\">\n <StampAssetCell\n asset={asset}\n armed={armedId === asset.id}\n onArm={() => arm(asset)}\n />\n {!isDefault(asset.libraryId) && (\n <button\n type=\"button\"\n onClick={() => void stamp.deleteAsset(asset.id)}\n title={t('demo.stampsRemoveStamp')}\n className=\"bg-surface border-border text-fg-muted hover:text-fg absolute end-1 top-1 grid h-5 w-5 place-items-center rounded-full border opacity-0 shadow-sm focus:opacity-100 group-hover:opacity-100\"\n >\n <Icon name=\"x\" size={12} />\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {(error || armedId) && (\n <div\n className={`border-border-subtle shrink-0 border-t px-3 py-2 text-xs ${\n error ? 'text-red-600' : 'text-fg-muted'\n }`}\n >\n {error ?? t('demo.stampsArmedHint')}\n </div>\n )}\n\n <div className=\"border-border-subtle shrink-0 border-t p-3\">\n <button\n type=\"button\"\n disabled={busy != null}\n onClick={() => fileRef.current?.click()}\n title={t('demo.stampsImportHint')}\n className=\"border-border text-fg hover:bg-hover flex w-full items-center justify-center gap-2 rounded-md border px-3 py-1.5 text-sm disabled:opacity-40\"\n >\n <Icon name=\"rubberStampPlus\" size={16} />\n {busy === 'importing' ? t('demo.stampsImporting') : t('demo.stampsImport')}\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"application/pdf\"\n className=\"hidden\"\n onChange={(event) => {\n const file = event.currentTarget.files?.[0];\n event.currentTarget.value = ''; // allow re-picking the same file\n if (file) importPdf(file);\n }}\n />\n </div>\n </div>\n );\n}\n\n/** One grid cell: the plugin's cached preview through the object-URL hook\n * (the DOM resource's lifetime belongs to the framework layer, not the\n * store). Image only — the artwork is the label; the label is the\n * tooltip for the curious. */\nfunction StampAssetCell({\n asset,\n armed,\n onArm,\n}: {\n asset: StampAsset;\n armed: boolean;\n onArm: () => void;\n}) {\n const url = useStampAssetPreviewUrl(asset.id);\n return (\n <button\n type=\"button\"\n onClick={onArm}\n title={asset.label}\n aria-pressed={armed}\n className={`flex aspect-square w-full items-center justify-center rounded-md border p-2 ${\n armed\n ? 'border-accent bg-accent-light ring-accent ring-2'\n : 'border-border-subtle hover:border-border hover:bg-hover'\n }`}\n >\n {url ? (\n <img src={url} alt={asset.label} className=\"max-h-full max-w-full object-contain\" />\n ) : (\n <span className=\"text-fg truncate text-sm\">{asset.label}</span>\n )}\n </button>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stamps-panel-CDO0FPyK.js","names":[],"sources":["../src/ui/stamps-panel.tsx"],"sourcesContent":["/**\n * The stamps sidebar (right panel). The stamp plugin owns the libraries, the\n * asset bytes and the cached previews; this panel is the picker over them:\n *\n * a library <select> (\"All stamps\" + one per library, shown once there\n * are two) → a two-column grid of thumbnails → click a stamp → `armAsset`\n * arms the annotation plugin's stamp tool → hovering a page ghosts the\n * exact placement → each click on a page places one.\n *\n * Deliberately not a file dialog: picking arbitrary image bytes is the Image\n * tool's job (a click-then-pick tool, `tool:image`). The stamp button\n * opens a library; a library is a set of reusable, named assets — the two\n * gestures are different, so they are different controls.\n *\n * The panel stays open while you place, so a stamp can be dropped on several\n * pages and swapped without a round trip through the toolbar. A command can\n * open it on a library (`annotation:stamp-from-selection` → \"My stamps\")\n * through the surface's open props.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { useInteractionState } from '@embedpdf/react/interaction';\nimport {\n useStamp,\n useStampAssetPreviewUrl,\n useStampAssets,\n useStampLibraries,\n type StampAsset,\n} from '@embedpdf/react/stamp';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useI18nState, useT } from '@embedpdf/react/i18n';\nimport { useStampSettings } from '../config-context';\nimport {\n DEFAULT_LIBRARY_ID,\n ensureDefaultLibrary,\n resolveStampsLocale,\n} from '../config/default-stamps';\nimport { Icon } from './icons';\nimport { restoreStampLibrariesOnce } from './stamp-store';\n\nconst ALL = 'all';\n\nexport function StampsPanel() {\n const t = useT();\n const stamp = useStamp();\n const { standard, sidebar } = useStampSettings();\n // Which catalogs this sidebar shows (`plugins.stamp.sidebar`): the plain stamps by\n // default — never the people's marks, which have their own panel.\n const libraries = useStampLibraries({ kind: sidebar ?? ['stamps'] });\n const assets = useStampAssets();\n const { activeToolId } = useInteractionState();\n const { locale } = useI18nState();\n const surface = useSurface('stamps');\n const fileRef = useRef<HTMLInputElement>(null);\n const [armedId, setArmedId] = useState<string | null>(null);\n const [busy, setBusy] = useState<'loading' | 'importing' | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [picked, setPicked] = useState<string>(ALL);\n\n // A command opened the panel on a library (the surface's `libraryId` prop).\n const openedOn = surface.props?.libraryId;\n useEffect(() => {\n if (typeof openedOn === 'string') setPicked(openedOn);\n }, [openedOn]);\n\n // First open: the user's stored libraries (the workspace store restores\n // them; this only awaits it), then the built-in library for this locale —\n // never at viewer boot, so a viewer whose user never opens this panel pays\n // nothing for it. A locale change while open swaps the built-in library;\n // the user's own are untouched.\n useEffect(() => {\n let live = true;\n setBusy('loading');\n restoreStampLibrariesOnce(stamp)\n .then(() => ensureDefaultLibrary(stamp, resolveStampsLocale(locale), standard))\n .catch((error: unknown) => {\n console.error('[embedpdf] default stamps failed:', error);\n if (live) setError(t('demo.stampsError'));\n })\n .finally(() => live && setBusy(null));\n return () => {\n live = false;\n };\n // `t` and `standard` are init-stable; only the locale re-runs this.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stamp, locale]);\n\n // The interaction hub owns tool state: leaving the stamp tool (picking\n // another tool, pressing Escape) un-highlights the gallery.\n useEffect(() => {\n if (activeToolId !== 'stamp') setArmedId(null);\n }, [activeToolId]);\n\n const arm = (asset: StampAsset) => {\n setError(null);\n setArmedId(asset.id);\n void stamp.armAsset(asset.id).catch((error) => {\n console.error('[embedpdf] arm stamp failed:', error);\n setArmedId(null);\n setError(t('demo.stampsArmError'));\n });\n };\n\n const importPdf = (file: File) => {\n setError(null);\n setBusy('importing');\n // The file name is only a fallback: an Acrobat-authored or previously\n // exported library names itself through its /Title.\n stamp\n .importLibrary(file, { name: file.name.replace(/\\.pdf$/i, '') })\n .then(({ library }) => setPicked(library.id))\n .catch((error) => {\n console.error('[embedpdf] stamp library import failed:', error);\n setError(t('demo.stampsImportError'));\n })\n .finally(() => setBusy(null));\n };\n\n /** The library as the PDF it is — title, registry, artwork — for Acrobat\n * or another viewer. */\n const exportPdf = async (libraryId: string, name: string) => {\n const bytes = await stamp.exportLibrary(libraryId).catch(() => null);\n if (!bytes) return;\n const blob = new Blob([bytes as BlobPart], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `${name || 'stamps'}.pdf`;\n anchor.click();\n URL.revokeObjectURL(url);\n };\n\n // A removed library falls back to \"All\"; the picker never names a ghost.\n // One library needs no picker: it is simply the selection (so its export\n // button is reachable).\n const selectedId =\n libraries.length === 1\n ? libraries[0].id\n : libraries.some((library) => library.id === picked)\n ? picked\n : ALL;\n const selected =\n selectedId === ALL ? null : (libraries.find((library) => library.id === selectedId) ?? null);\n const shown =\n selectedId === ALL ? assets : assets.filter((asset) => asset.libraryId === selectedId);\n const isDefault = (libraryId: string) => libraryId === DEFAULT_LIBRARY_ID;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n {libraries.length > 0 && (\n <div className=\"border-border-subtle flex items-center gap-1 border-b p-2\">\n {libraries.length > 1 ? (\n <select\n value={selectedId}\n onChange={(event) => setPicked(event.target.value)}\n aria-label={t('panels.stamps')}\n className=\"border-border bg-surface text-fg min-w-0 flex-1 rounded border px-2 py-1.5 text-sm\"\n >\n <option value={ALL}>{t('demo.stampsAll')}</option>\n {libraries.map((library) => (\n <option key={library.id} value={library.id}>\n {library.name}\n </option>\n ))}\n </select>\n ) : (\n <span className=\"text-fg-muted min-w-0 flex-1 truncate px-1 text-xs font-semibold uppercase tracking-wide\">\n {libraries[0].name}\n </span>\n )}\n {selected && (\n <>\n <button\n type=\"button\"\n onClick={() => exportPdf(selected.id, selected.name)}\n title={t('demo.stampsExportLibrary')}\n className=\"text-fg-muted hover:text-fg grid h-7 w-7 shrink-0 place-items-center rounded\"\n >\n <Icon name=\"download\" size={14} />\n </button>\n {!isDefault(selected.id) && (\n <button\n type=\"button\"\n onClick={() => void stamp.deleteLibrary(selected.id)}\n title={t('demo.stampsRemoveLibrary')}\n className=\"text-fg-muted hover:text-fg grid h-7 w-7 shrink-0 place-items-center rounded\"\n >\n <Icon name=\"trash\" size={14} />\n </button>\n )}\n </>\n )}\n </div>\n )}\n\n <div className=\"min-h-0 flex-1 overflow-y-auto p-3\">\n {busy === 'loading' && shown.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-10 text-center\">\n <div className=\"border-border-subtle border-t-accent h-6 w-6 animate-spin rounded-full border-2\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.stampsLoading')}</p>\n </div>\n ) : shown.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-10 text-center\">\n <Icon name=\"rubberStamp\" size={32} className=\"text-fg-muted\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.stampsEmpty')}</p>\n </div>\n ) : (\n <ul className=\"grid grid-cols-2 gap-3\">\n {shown.map((asset) => (\n <li key={asset.id} className=\"group relative\">\n <StampAssetCell\n asset={asset}\n armed={armedId === asset.id}\n onArm={() => arm(asset)}\n />\n {!isDefault(asset.libraryId) && (\n <button\n type=\"button\"\n onClick={() => void stamp.deleteAsset(asset.id)}\n title={t('demo.stampsRemoveStamp')}\n className=\"bg-surface border-border text-fg-muted hover:text-fg absolute end-1 top-1 grid h-5 w-5 place-items-center rounded-full border opacity-0 shadow-sm focus:opacity-100 group-hover:opacity-100\"\n >\n <Icon name=\"x\" size={12} />\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {(error || armedId) && (\n <div\n className={`border-border-subtle shrink-0 border-t px-3 py-2 text-xs ${\n error ? 'text-red-600' : 'text-fg-muted'\n }`}\n >\n {error ?? t('demo.stampsArmedHint')}\n </div>\n )}\n\n <div className=\"border-border-subtle shrink-0 border-t p-3\">\n <button\n type=\"button\"\n disabled={busy != null}\n onClick={() => fileRef.current?.click()}\n title={t('demo.stampsImportHint')}\n className=\"border-border text-fg hover:bg-hover flex w-full items-center justify-center gap-2 rounded-md border px-3 py-1.5 text-sm disabled:opacity-40\"\n >\n <Icon name=\"rubberStampPlus\" size={16} />\n {busy === 'importing' ? t('demo.stampsImporting') : t('demo.stampsImport')}\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"application/pdf\"\n className=\"hidden\"\n onChange={(event) => {\n const file = event.currentTarget.files?.[0];\n event.currentTarget.value = ''; // allow re-picking the same file\n if (file) importPdf(file);\n }}\n />\n </div>\n </div>\n );\n}\n\n/** One grid cell: the plugin's cached preview through the object-URL hook\n * (the DOM resource's lifetime belongs to the framework layer, not the\n * store). Image only — the artwork is the label; the label is the\n * tooltip for the curious. */\nfunction StampAssetCell({\n asset,\n armed,\n onArm,\n}: {\n asset: StampAsset;\n armed: boolean;\n onArm: () => void;\n}) {\n const url = useStampAssetPreviewUrl(asset.id);\n return (\n <button\n type=\"button\"\n onClick={onArm}\n title={asset.label}\n aria-pressed={armed}\n className={`flex aspect-square w-full items-center justify-center rounded-md border p-2 ${\n armed\n ? 'border-accent bg-accent-light ring-accent ring-2'\n : 'border-border-subtle hover:border-border hover:bg-hover'\n }`}\n >\n {url ? (\n <img src={url} alt={asset.label} className=\"max-h-full max-w-full object-contain\" />\n ) : (\n <span className=\"text-fg truncate text-sm\">{asset.label}</span>\n )}\n </button>\n );\n}\n"],"mappings":"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"}
|