@caribeng/ui 22.2.0 → 22.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +311 -231
- package/fesm2022/caribeng-ui-accordion.mjs +2 -2
- package/fesm2022/caribeng-ui-account-picker.mjs +533 -0
- package/fesm2022/caribeng-ui-aging.mjs +488 -0
- package/fesm2022/{caribeng-ui-caribe-alert.mjs → caribeng-ui-alert.mjs} +45 -45
- package/fesm2022/caribeng-ui-amount.mjs +249 -0
- package/fesm2022/caribeng-ui-anchor.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-animation-lottie.mjs → caribeng-ui-animation-lottie.mjs} +41 -41
- package/fesm2022/caribeng-ui-audit-log.mjs +323 -0
- package/fesm2022/caribeng-ui-avatar.mjs +4 -4
- package/fesm2022/caribeng-ui-badge.mjs +8 -2
- package/fesm2022/caribeng-ui-breadcrumb.mjs +26 -9
- package/fesm2022/{caribeng-ui-caribe-button-group.mjs → caribeng-ui-button-group.mjs} +15 -15
- package/fesm2022/caribeng-ui-button.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-card-content.mjs → caribeng-ui-card-content.mjs} +39 -39
- package/fesm2022/{caribeng-ui-caribe-card-move.mjs → caribeng-ui-card-move.mjs} +65 -65
- package/fesm2022/{caribeng-ui-caribe-card-primary.mjs → caribeng-ui-card-primary.mjs} +31 -31
- package/fesm2022/{caribeng-ui-caribe-card-select.mjs → caribeng-ui-card-select.mjs} +67 -67
- package/fesm2022/caribeng-ui-carousel.mjs +2 -2
- package/fesm2022/caribeng-ui-cascadeselect.mjs +45 -9
- package/fesm2022/caribeng-ui-chart.mjs +8 -5
- package/fesm2022/caribeng-ui-chat.mjs +1303 -0
- package/fesm2022/{caribeng-ui-caribe-coachmark.mjs → caribeng-ui-coachmark.mjs} +85 -85
- package/fesm2022/caribeng-ui-code-block.mjs +332 -0
- package/fesm2022/caribeng-ui-colorpicker.mjs +99 -5
- package/fesm2022/caribeng-ui-command-palette.mjs +476 -0
- package/fesm2022/caribeng-ui-comments.mjs +864 -0
- package/fesm2022/caribeng-ui-confirmdialog.mjs +78 -13
- package/fesm2022/caribeng-ui-confirmpopup.mjs +91 -16
- package/fesm2022/caribeng-ui-contextmenu.mjs +8 -4
- package/fesm2022/caribeng-ui-copy-button.mjs +230 -0
- package/fesm2022/caribeng-ui-datagrid.mjs +1635 -0
- package/fesm2022/caribeng-ui-dataview.mjs +6 -3
- package/fesm2022/caribeng-ui-datepicker.mjs +2 -2
- package/fesm2022/caribeng-ui-dock.mjs +52 -12
- package/fesm2022/caribeng-ui-document.mjs +495 -0
- package/fesm2022/{caribeng-ui-caribe-dots-indicator.mjs → caribeng-ui-dots-indicator.mjs} +41 -41
- package/fesm2022/caribeng-ui-drawer.mjs +9 -4
- package/fesm2022/caribeng-ui-dynamic-form.mjs +1581 -0
- package/fesm2022/caribeng-ui-editor.mjs +2324 -1311
- package/fesm2022/{caribeng-ui-caribe-expansion-panel.mjs → caribeng-ui-expansion-panel.mjs} +39 -39
- package/fesm2022/{caribeng-ui-caribe-fab-menu.mjs → caribeng-ui-fab-menu.mjs} +75 -75
- package/fesm2022/caribeng-ui-fieldset.mjs +2 -2
- package/fesm2022/caribeng-ui-file-card.mjs +134 -17
- package/fesm2022/{caribeng-ui-caribe-file-download.mjs → caribeng-ui-file-download.mjs} +63 -63
- package/fesm2022/caribeng-ui-financial-report.mjs +380 -0
- package/fesm2022/{caribeng-ui-caribe-float-menu.mjs → caribeng-ui-float-menu.mjs} +31 -31
- package/fesm2022/caribeng-ui-floatlabel.mjs +2 -2
- package/fesm2022/caribeng-ui-flow.mjs +1508 -0
- package/fesm2022/caribeng-ui-folder-card.mjs +122 -12
- package/fesm2022/{caribeng-ui-caribe-footer.mjs → caribeng-ui-footer.mjs} +19 -19
- package/fesm2022/caribeng-ui-gantt.mjs +1094 -0
- package/fesm2022/{caribeng-ui-caribe-header.mjs → caribeng-ui-header.mjs} +49 -49
- package/fesm2022/{caribeng-ui-caribe-icon-button.mjs → caribeng-ui-icon-button.mjs} +23 -23
- package/fesm2022/caribeng-ui-image-cropper.mjs +671 -0
- package/fesm2022/caribeng-ui-import-wizard.mjs +746 -0
- package/fesm2022/caribeng-ui-infinite-scroll.mjs +226 -0
- package/fesm2022/caribeng-ui-inlinemessage.mjs +2 -2
- package/fesm2022/caribeng-ui-input-number.mjs +22 -6
- package/fesm2022/{caribeng-ui-caribe-input-search.mjs → caribeng-ui-input-search.mjs} +65 -65
- package/fesm2022/{caribeng-ui-caribe-input-token.mjs → caribeng-ui-input-token.mjs} +59 -59
- package/fesm2022/caribeng-ui-inputmask.mjs +8 -2
- package/fesm2022/caribeng-ui-inputotp.mjs +2 -2
- package/fesm2022/caribeng-ui-journal-entry.mjs +340 -0
- package/fesm2022/caribeng-ui-kanban.mjs +4612 -0
- package/fesm2022/caribeng-ui-kbd.mjs +122 -0
- package/fesm2022/caribeng-ui-kpi.mjs +189 -0
- package/fesm2022/{caribeng-ui-caribe-link.mjs → caribeng-ui-link.mjs} +37 -37
- package/fesm2022/caribeng-ui-masonry.mjs +93 -0
- package/fesm2022/caribeng-ui-media-player.mjs +821 -0
- package/fesm2022/caribeng-ui-megamenu.mjs +13 -9
- package/fesm2022/caribeng-ui-mentions.mjs +495 -0
- package/fesm2022/caribeng-ui-menu.mjs +8 -4
- package/fesm2022/caribeng-ui-menubar.mjs +9 -5
- package/fesm2022/caribeng-ui-message.mjs +6 -3
- package/fesm2022/caribeng-ui-notification-center.mjs +636 -0
- package/fesm2022/{caribeng-ui-caribe-off-canvas.mjs → caribeng-ui-off-canvas.mjs} +55 -55
- package/fesm2022/{caribeng-ui-caribe-onboarding.mjs → caribeng-ui-onboarding.mjs} +105 -105
- package/fesm2022/caribeng-ui-orderlist.mjs +2 -2
- package/fesm2022/caribeng-ui-organizationchart.mjs +6 -10
- package/fesm2022/caribeng-ui-panel.mjs +6 -6
- package/fesm2022/caribeng-ui-panelmenu.mjs +9 -6
- package/fesm2022/caribeng-ui-pdfviewer.mjs +1755 -25
- package/fesm2022/caribeng-ui-period-picker.mjs +637 -0
- package/fesm2022/caribeng-ui-phone-input.mjs +688 -0
- package/fesm2022/caribeng-ui-picklist.mjs +2 -2
- package/fesm2022/caribeng-ui-pivot.mjs +419 -0
- package/fesm2022/caribeng-ui-pricing.mjs +263 -69
- package/fesm2022/caribeng-ui-qrcode.mjs +564 -0
- package/fesm2022/caribeng-ui-rating.mjs +14 -17
- package/fesm2022/caribeng-ui-reconciliation.mjs +386 -0
- package/fesm2022/caribeng-ui-ripple.mjs +2 -0
- package/fesm2022/caribeng-ui-scheduler.mjs +1027 -0
- package/fesm2022/caribeng-ui-scrolltop.mjs +3 -1
- package/fesm2022/caribeng-ui-select.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-shortcut.mjs → caribeng-ui-shortcut.mjs} +29 -29
- package/fesm2022/caribeng-ui-sidebar.mjs +573 -0
- package/fesm2022/caribeng-ui-signature-pad.mjs +654 -0
- package/fesm2022/{caribeng-ui-caribe-status.mjs → caribeng-ui-status.mjs} +11 -11
- package/fesm2022/{caribeng-ui-caribe-step-indicator.mjs → caribeng-ui-step-indicator.mjs} +53 -53
- package/fesm2022/caribeng-ui-stepper.mjs +12 -5
- package/fesm2022/caribeng-ui-steps.mjs +2 -2
- package/fesm2022/caribeng-ui-table.mjs +333 -19
- package/fesm2022/caribeng-ui-tabmenu.mjs +10 -6
- package/fesm2022/caribeng-ui-tabs.mjs +2 -2
- package/fesm2022/{caribeng-ui-caribe-tag-button.mjs → caribeng-ui-tag-button.mjs} +25 -25
- package/fesm2022/caribeng-ui-tag.mjs +2 -2
- package/fesm2022/caribeng-ui-tieredmenu.mjs +111 -21
- package/fesm2022/{caribeng-ui-caribe-tracker.mjs → caribeng-ui-tracker.mjs} +29 -29
- package/fesm2022/{caribeng-ui-caribe-transaction-status.mjs → caribeng-ui-transaction-status.mjs} +11 -11
- package/fesm2022/caribeng-ui-treeselect.mjs +44 -9
- package/fesm2022/caribeng-ui-treetable.mjs +236 -17
- package/fesm2022/{caribeng-ui-caribe-voucher.mjs → caribeng-ui-voucher.mjs} +45 -45
- package/fesm2022/caribeng-ui-xlsx.mjs +486 -0
- package/fesm2022/caribeng-ui.mjs +1568 -1
- package/package.json +258 -178
- package/schematics/collection.json +5 -0
- package/schematics/migrate-from-primeng/core-icons.json +1 -0
- package/schematics/migrate-from-primeng/icons.js +269 -0
- package/schematics/migrate-from-primeng/index.js +290 -0
- package/schematics/migrate-from-primeng/mappings/button.js +93 -0
- package/schematics/migrate-from-primeng/mappings/card.js +33 -0
- package/schematics/migrate-from-primeng/mappings/checkbox.js +44 -0
- package/schematics/migrate-from-primeng/mappings/confirm.js +221 -0
- package/schematics/migrate-from-primeng/mappings/datepicker.js +121 -0
- package/schematics/migrate-from-primeng/mappings/dialog.js +84 -0
- package/schematics/migrate-from-primeng/mappings/index.js +88 -0
- package/schematics/migrate-from-primeng/mappings/inputnumber.js +62 -0
- package/schematics/migrate-from-primeng/mappings/inputtext.js +60 -0
- package/schematics/migrate-from-primeng/mappings/menu.js +468 -0
- package/schematics/migrate-from-primeng/mappings/multiselect.js +49 -0
- package/schematics/migrate-from-primeng/mappings/radiobutton.js +22 -0
- package/schematics/migrate-from-primeng/mappings/rules.js +206 -0
- package/schematics/migrate-from-primeng/mappings/select.js +97 -0
- package/schematics/migrate-from-primeng/mappings/service-calls.js +100 -0
- package/schematics/migrate-from-primeng/mappings/table.js +613 -0
- package/schematics/migrate-from-primeng/mappings/tabs.js +225 -0
- package/schematics/migrate-from-primeng/mappings/tag.js +29 -0
- package/schematics/migrate-from-primeng/mappings/textarea.js +44 -0
- package/schematics/migrate-from-primeng/mappings/toast.js +173 -0
- package/schematics/migrate-from-primeng/mappings/toggleswitch.js +37 -0
- package/schematics/migrate-from-primeng/mappings/tooltip.js +44 -0
- package/schematics/migrate-from-primeng/mappings/types.js +10 -0
- package/schematics/migrate-from-primeng/report.js +79 -0
- package/schematics/migrate-from-primeng/schema.js +2 -0
- package/schematics/migrate-from-primeng/schema.json +34 -0
- package/schematics/migrate-from-primeng/template.js +387 -0
- package/schematics/migrate-from-primeng/todo.js +5 -0
- package/schematics/migrate-from-primeng/typescript.js +442 -0
- package/schematics/migrate-from-primeng/workspace.js +117 -0
- package/schematics/ng-add/index.js +16 -1
- package/types/caribeng-ui-account-picker.d.ts +142 -0
- package/types/caribeng-ui-aging.d.ts +123 -0
- package/types/{caribeng-ui-caribe-alert.d.ts → caribeng-ui-alert.d.ts} +2 -2
- package/types/caribeng-ui-amount.d.ts +82 -0
- package/types/{caribeng-ui-caribe-animation-lottie.d.ts → caribeng-ui-animation-lottie.d.ts} +2 -2
- package/types/caribeng-ui-audit-log.d.ts +86 -0
- package/types/caribeng-ui-badge.d.ts +3 -1
- package/types/caribeng-ui-breadcrumb.d.ts +9 -1
- package/types/{caribeng-ui-caribe-button-group.d.ts → caribeng-ui-button-group.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-content.d.ts → caribeng-ui-card-content.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-move.d.ts → caribeng-ui-card-move.d.ts} +1 -1
- package/types/{caribeng-ui-caribe-card-primary.d.ts → caribeng-ui-card-primary.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-card-select.d.ts → caribeng-ui-card-select.d.ts} +2 -2
- package/types/caribeng-ui-cascadeselect.d.ts +6 -0
- package/types/caribeng-ui-chart.d.ts +3 -1
- package/types/caribeng-ui-chat.d.ts +299 -0
- package/types/{caribeng-ui-caribe-coachmark.d.ts → caribeng-ui-coachmark.d.ts} +2 -2
- package/types/caribeng-ui-code-block.d.ts +65 -0
- package/types/caribeng-ui-colorpicker.d.ts +5 -1
- package/types/caribeng-ui-command-palette.d.ts +133 -0
- package/types/caribeng-ui-comments.d.ts +214 -0
- package/types/caribeng-ui-confirmdialog.d.ts +34 -2
- package/types/caribeng-ui-confirmpopup.d.ts +39 -2
- package/types/caribeng-ui-contextmenu.d.ts +7 -0
- package/types/caribeng-ui-copy-button.d.ts +90 -0
- package/types/caribeng-ui-datagrid.d.ts +269 -0
- package/types/caribeng-ui-dataview.d.ts +2 -0
- package/types/caribeng-ui-dock.d.ts +13 -1
- package/types/caribeng-ui-document.d.ts +138 -0
- package/types/{caribeng-ui-caribe-dots-indicator.d.ts → caribeng-ui-dots-indicator.d.ts} +2 -2
- package/types/caribeng-ui-drawer.d.ts +3 -1
- package/types/caribeng-ui-dynamic-form.d.ts +409 -0
- package/types/caribeng-ui-editor.d.ts +110 -12
- package/types/{caribeng-ui-caribe-expansion-panel.d.ts → caribeng-ui-expansion-panel.d.ts} +1 -1
- package/types/{caribeng-ui-caribe-fab-menu.d.ts → caribeng-ui-fab-menu.d.ts} +2 -2
- package/types/caribeng-ui-file-card.d.ts +27 -2
- package/types/{caribeng-ui-caribe-file-download.d.ts → caribeng-ui-file-download.d.ts} +1 -1
- package/types/caribeng-ui-financial-report.d.ts +102 -0
- package/types/{caribeng-ui-caribe-float-menu.d.ts → caribeng-ui-float-menu.d.ts} +2 -2
- package/types/caribeng-ui-flow.d.ts +228 -0
- package/types/caribeng-ui-folder-card.d.ts +27 -5
- package/types/{caribeng-ui-caribe-footer.d.ts → caribeng-ui-footer.d.ts} +2 -2
- package/types/caribeng-ui-gantt.d.ts +244 -0
- package/types/{caribeng-ui-caribe-header.d.ts → caribeng-ui-header.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-icon-button.d.ts → caribeng-ui-icon-button.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-illustration.d.ts → caribeng-ui-illustration.d.ts} +1 -1
- package/types/caribeng-ui-image-cropper.d.ts +169 -0
- package/types/caribeng-ui-import-wizard.d.ts +149 -0
- package/types/caribeng-ui-infinite-scroll.d.ts +75 -0
- package/types/caribeng-ui-input-number.d.ts +1 -1
- package/types/{caribeng-ui-caribe-input-search.d.ts → caribeng-ui-input-search.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-input-token.d.ts → caribeng-ui-input-token.d.ts} +2 -2
- package/types/caribeng-ui-inputmask.d.ts +3 -1
- package/types/caribeng-ui-journal-entry.d.ts +110 -0
- package/types/caribeng-ui-kanban.d.ts +783 -0
- package/types/caribeng-ui-kbd.d.ts +36 -0
- package/types/caribeng-ui-kpi.d.ts +64 -0
- package/types/{caribeng-ui-caribe-link.d.ts → caribeng-ui-link.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-logo.d.ts → caribeng-ui-logo.d.ts} +1 -1
- package/types/caribeng-ui-masonry.d.ts +32 -0
- package/types/caribeng-ui-media-player.d.ts +140 -0
- package/types/caribeng-ui-megamenu.d.ts +11 -0
- package/types/caribeng-ui-mentions.d.ts +127 -0
- package/types/caribeng-ui-menu.d.ts +7 -0
- package/types/caribeng-ui-menubar.d.ts +7 -0
- package/types/caribeng-ui-message.d.ts +2 -0
- package/types/caribeng-ui-notification-center.d.ts +153 -0
- package/types/{caribeng-ui-caribe-off-canvas.d.ts → caribeng-ui-off-canvas.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-onboarding.d.ts → caribeng-ui-onboarding.d.ts} +2 -2
- package/types/caribeng-ui-panelmenu.d.ts +7 -0
- package/types/caribeng-ui-pdfviewer.d.ts +245 -5
- package/types/caribeng-ui-period-picker.d.ts +148 -0
- package/types/caribeng-ui-phone-input.d.ts +168 -0
- package/types/caribeng-ui-pivot.d.ts +116 -0
- package/types/caribeng-ui-pricing.d.ts +41 -4
- package/types/caribeng-ui-qrcode.d.ts +88 -0
- package/types/caribeng-ui-reconciliation.d.ts +109 -0
- package/types/caribeng-ui-scheduler.d.ts +188 -0
- package/types/{caribeng-ui-caribe-shortcut.d.ts → caribeng-ui-shortcut.d.ts} +2 -2
- package/types/caribeng-ui-sidebar.d.ts +167 -0
- package/types/caribeng-ui-signature-pad.d.ts +151 -0
- package/types/{caribeng-ui-caribe-status.d.ts → caribeng-ui-status.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-step-indicator.d.ts → caribeng-ui-step-indicator.d.ts} +2 -2
- package/types/caribeng-ui-stepper.d.ts +2 -0
- package/types/caribeng-ui-table.d.ts +67 -3
- package/types/caribeng-ui-tabmenu.d.ts +7 -0
- package/types/{caribeng-ui-caribe-tag-button.d.ts → caribeng-ui-tag-button.d.ts} +2 -2
- package/types/caribeng-ui-tieredmenu.d.ts +17 -1
- package/types/{caribeng-ui-caribe-tracker.d.ts → caribeng-ui-tracker.d.ts} +2 -2
- package/types/{caribeng-ui-caribe-transaction-status.d.ts → caribeng-ui-transaction-status.d.ts} +2 -2
- package/types/caribeng-ui-treeselect.d.ts +6 -0
- package/types/caribeng-ui-treetable.d.ts +67 -2
- package/types/{caribeng-ui-caribe-voucher.d.ts → caribeng-ui-voucher.d.ts} +2 -2
- package/types/caribeng-ui-xlsx.d.ts +79 -0
- package/types/caribeng-ui.d.ts +985 -2
- package/fesm2022/caribeng-ui-caribe-calendar.mjs +0 -92
- package/fesm2022/caribeng-ui-caribe-circle-loading.mjs +0 -130
- package/fesm2022/caribeng-ui-caribe-data-table.mjs +0 -94
- package/fesm2022/caribeng-ui-caribe-file-select.mjs +0 -88
- package/fesm2022/caribeng-ui-caribe-inline-alert.mjs +0 -100
- package/fesm2022/caribeng-ui-caribe-input-date.mjs +0 -138
- package/fesm2022/caribeng-ui-caribe-input-select.mjs +0 -154
- package/fesm2022/caribeng-ui-caribe-loader.mjs +0 -48
- package/fesm2022/caribeng-ui-caribe-modal.mjs +0 -119
- package/fesm2022/caribeng-ui-caribe-pictogram.mjs +0 -52
- package/fesm2022/caribeng-ui-caribe-pop-over.mjs +0 -104
- package/fesm2022/caribeng-ui-caribe-preloader.mjs +0 -57
- package/fesm2022/caribeng-ui-caribe-progress-bar.mjs +0 -84
- package/fesm2022/caribeng-ui-caribe-stroke.mjs +0 -69
- package/fesm2022/caribeng-ui-caribe-switch.mjs +0 -182
- package/styles/caribeng.css +0 -380
- package/styles/scss/_mixins.scss +0 -46
- package/styles/scss/_overlay.scss +0 -15
- package/styles/scss/_tokens.scss +0 -267
- package/styles/scss/_utilities.scss +0 -73
- package/styles/scss/_variables.scss +0 -33
- package/styles/scss/index.scss +0 -16
- package/types/caribeng-ui-caribe-calendar.d.ts +0 -27
- package/types/caribeng-ui-caribe-circle-loading.d.ts +0 -28
- package/types/caribeng-ui-caribe-data-table.d.ts +0 -26
- package/types/caribeng-ui-caribe-file-select.d.ts +0 -31
- package/types/caribeng-ui-caribe-inline-alert.d.ts +0 -28
- package/types/caribeng-ui-caribe-input-date.d.ts +0 -40
- package/types/caribeng-ui-caribe-input-select.d.ts +0 -47
- package/types/caribeng-ui-caribe-loader.d.ts +0 -22
- package/types/caribeng-ui-caribe-modal.d.ts +0 -21
- package/types/caribeng-ui-caribe-pictogram.d.ts +0 -15
- package/types/caribeng-ui-caribe-pop-over.d.ts +0 -17
- package/types/caribeng-ui-caribe-preloader.d.ts +0 -24
- package/types/caribeng-ui-caribe-progress-bar.d.ts +0 -28
- package/types/caribeng-ui-caribe-stroke.d.ts +0 -17
- package/types/caribeng-ui-caribe-switch.d.ts +0 -55
- /package/fesm2022/{caribeng-ui-caribe-illustration.mjs → caribeng-ui-illustration.mjs} +0 -0
- /package/fesm2022/{caribeng-ui-caribe-logo.mjs → caribeng-ui-logo.mjs} +0 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { injectCbTranslation } from '@caribeng/ui';
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Codificador QR propio de CaribeNG (ISO/IEC 18004), sin dependencias.
|
|
7
|
+
* Modos numérico, alfanumérico y byte (UTF-8), versiones 1–40, niveles de
|
|
8
|
+
* corrección L/M/Q/H y elección automática de la máscara con menor penalización.
|
|
9
|
+
*/
|
|
10
|
+
// --- Tablas del estándar, indexadas por [nivel][versión] (índice 0 sin uso) ---
|
|
11
|
+
const EC_ORDER = ['L', 'M', 'Q', 'H'];
|
|
12
|
+
/** Bits del nivel en la información de formato. */
|
|
13
|
+
const EC_FORMAT_BITS = { L: 1, M: 0, Q: 3, H: 2 };
|
|
14
|
+
const EC_CODEWORDS_PER_BLOCK = {
|
|
15
|
+
L: [0, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
|
16
|
+
M: [0, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28],
|
|
17
|
+
Q: [0, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
|
18
|
+
H: [0, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
|
19
|
+
};
|
|
20
|
+
const EC_BLOCKS = {
|
|
21
|
+
L: [0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25],
|
|
22
|
+
M: [0, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49],
|
|
23
|
+
Q: [0, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68],
|
|
24
|
+
H: [0, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81],
|
|
25
|
+
};
|
|
26
|
+
const ALPHANUMERIC = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
|
|
27
|
+
const MODE_INDICATOR = { numeric: 0b0001, alphanumeric: 0b0010, byte: 0b0100 };
|
|
28
|
+
/** Bits del contador de caracteres para las versiones 1–9, 10–26 y 27–40. */
|
|
29
|
+
const COUNT_BITS = {
|
|
30
|
+
numeric: [10, 12, 14],
|
|
31
|
+
alphanumeric: [9, 11, 13],
|
|
32
|
+
byte: [8, 16, 16],
|
|
33
|
+
};
|
|
34
|
+
// --- Aritmética en GF(256) con el polinomio x^8 + x^4 + x^3 + x^2 + 1 ---
|
|
35
|
+
const GF_EXP = new Uint8Array(512);
|
|
36
|
+
const GF_LOG = new Uint8Array(256);
|
|
37
|
+
{
|
|
38
|
+
let x = 1;
|
|
39
|
+
for (let i = 0; i < 255; i++) {
|
|
40
|
+
GF_EXP[i] = x;
|
|
41
|
+
GF_LOG[x] = i;
|
|
42
|
+
x <<= 1;
|
|
43
|
+
if (x & 0x100)
|
|
44
|
+
x ^= 0x11d;
|
|
45
|
+
}
|
|
46
|
+
for (let i = 255; i < 512; i++)
|
|
47
|
+
GF_EXP[i] = GF_EXP[i - 255];
|
|
48
|
+
}
|
|
49
|
+
function gfMul(a, b) {
|
|
50
|
+
return a === 0 || b === 0 ? 0 : GF_EXP[GF_LOG[a] + GF_LOG[b]];
|
|
51
|
+
}
|
|
52
|
+
/** Coeficientes (sin el término principal) del generador Reed-Solomon de grado `degree`. */
|
|
53
|
+
function rsGenerator(degree) {
|
|
54
|
+
let poly = [1];
|
|
55
|
+
for (let i = 0; i < degree; i++) {
|
|
56
|
+
const next = new Array(poly.length + 1).fill(0);
|
|
57
|
+
for (let j = 0; j < poly.length; j++) {
|
|
58
|
+
next[j] ^= poly[j];
|
|
59
|
+
next[j + 1] ^= gfMul(poly[j], GF_EXP[i]);
|
|
60
|
+
}
|
|
61
|
+
poly = next;
|
|
62
|
+
}
|
|
63
|
+
return poly.slice(1);
|
|
64
|
+
}
|
|
65
|
+
/** Codewords de corrección de `data` (resto de la división por el generador). */
|
|
66
|
+
function cbQrReedSolomon(data, degree) {
|
|
67
|
+
const generator = rsGenerator(degree);
|
|
68
|
+
const remainder = new Array(degree).fill(0);
|
|
69
|
+
for (const byte of data) {
|
|
70
|
+
const factor = byte ^ remainder.shift();
|
|
71
|
+
remainder.push(0);
|
|
72
|
+
for (let i = 0; i < degree; i++)
|
|
73
|
+
remainder[i] ^= gfMul(generator[i], factor);
|
|
74
|
+
}
|
|
75
|
+
return remainder;
|
|
76
|
+
}
|
|
77
|
+
// --- Capacidad ---
|
|
78
|
+
/** Módulos disponibles para datos y corrección (sin patrones de función ni formato). */
|
|
79
|
+
function rawDataModules(version) {
|
|
80
|
+
let modules = (16 * version + 128) * version + 64;
|
|
81
|
+
if (version >= 2) {
|
|
82
|
+
const align = Math.floor(version / 7) + 2;
|
|
83
|
+
modules -= (25 * align - 10) * align - 55;
|
|
84
|
+
if (version >= 7)
|
|
85
|
+
modules -= 36;
|
|
86
|
+
}
|
|
87
|
+
return modules;
|
|
88
|
+
}
|
|
89
|
+
function dataCodewords(version, ec) {
|
|
90
|
+
return Math.floor(rawDataModules(version) / 8) - EC_CODEWORDS_PER_BLOCK[ec][version] * EC_BLOCKS[ec][version];
|
|
91
|
+
}
|
|
92
|
+
// --- Segmento de datos ---
|
|
93
|
+
class BitBuffer {
|
|
94
|
+
constructor() {
|
|
95
|
+
this.bits = [];
|
|
96
|
+
}
|
|
97
|
+
push(value, length) {
|
|
98
|
+
for (let i = length - 1; i >= 0; i--)
|
|
99
|
+
this.bits.push((value >>> i) & 1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function chooseMode(text) {
|
|
103
|
+
if (/^\d*$/.test(text))
|
|
104
|
+
return 'numeric';
|
|
105
|
+
if ([...text].every((c) => ALPHANUMERIC.includes(c)))
|
|
106
|
+
return 'alphanumeric';
|
|
107
|
+
return 'byte';
|
|
108
|
+
}
|
|
109
|
+
function countBits(mode, version) {
|
|
110
|
+
return COUNT_BITS[mode][version <= 9 ? 0 : version <= 26 ? 1 : 2];
|
|
111
|
+
}
|
|
112
|
+
/** Bits del contenido (sin modo ni contador) y número de caracteres a declarar. */
|
|
113
|
+
function encodeContent(text, mode) {
|
|
114
|
+
const bits = new BitBuffer();
|
|
115
|
+
if (mode === 'numeric') {
|
|
116
|
+
for (let i = 0; i < text.length; i += 3) {
|
|
117
|
+
const group = text.slice(i, i + 3);
|
|
118
|
+
bits.push(Number(group), group.length * 3 + 1);
|
|
119
|
+
}
|
|
120
|
+
return { bits, count: text.length };
|
|
121
|
+
}
|
|
122
|
+
if (mode === 'alphanumeric') {
|
|
123
|
+
for (let i = 0; i < text.length; i += 2) {
|
|
124
|
+
const a = ALPHANUMERIC.indexOf(text[i]);
|
|
125
|
+
if (i + 1 < text.length)
|
|
126
|
+
bits.push(a * 45 + ALPHANUMERIC.indexOf(text[i + 1]), 11);
|
|
127
|
+
else
|
|
128
|
+
bits.push(a, 6);
|
|
129
|
+
}
|
|
130
|
+
return { bits, count: text.length };
|
|
131
|
+
}
|
|
132
|
+
const bytes = new TextEncoder().encode(text);
|
|
133
|
+
for (const b of bytes)
|
|
134
|
+
bits.push(b, 8);
|
|
135
|
+
return { bits, count: bytes.length };
|
|
136
|
+
}
|
|
137
|
+
// --- Matriz ---
|
|
138
|
+
function alignmentPositions(version) {
|
|
139
|
+
if (version === 1)
|
|
140
|
+
return [];
|
|
141
|
+
const count = Math.floor(version / 7) + 2;
|
|
142
|
+
const size = version * 4 + 17;
|
|
143
|
+
const step = version === 32 ? 26 : Math.ceil((version * 4 + 4) / (count * 2 - 2)) * 2;
|
|
144
|
+
const positions = [6];
|
|
145
|
+
for (let i = 0, pos = size - 7; i < count - 1; i++, pos -= step)
|
|
146
|
+
positions.splice(1, 0, pos);
|
|
147
|
+
return positions;
|
|
148
|
+
}
|
|
149
|
+
/** Resto BCH: `value` desplazado `degree` bits módulo `generator`. */
|
|
150
|
+
function bchRemainder(value, generator, degree) {
|
|
151
|
+
let rem = value << degree;
|
|
152
|
+
for (let bit = 31 - Math.clz32(rem); bit >= degree; bit--) {
|
|
153
|
+
if ((rem >>> bit) & 1)
|
|
154
|
+
rem ^= generator << (bit - degree);
|
|
155
|
+
}
|
|
156
|
+
return rem;
|
|
157
|
+
}
|
|
158
|
+
/** 15 bits de formato (nivel + máscara), ya con la máscara XOR del estándar. */
|
|
159
|
+
function cbQrFormatBits(ec, mask) {
|
|
160
|
+
const data = (EC_FORMAT_BITS[ec] << 3) | mask;
|
|
161
|
+
return ((data << 10) | bchRemainder(data, 0x537, 10)) ^ 0x5412;
|
|
162
|
+
}
|
|
163
|
+
const MASKS = [
|
|
164
|
+
(x, y) => (x + y) % 2 === 0,
|
|
165
|
+
(_x, y) => y % 2 === 0,
|
|
166
|
+
(x) => x % 3 === 0,
|
|
167
|
+
(x, y) => (x + y) % 3 === 0,
|
|
168
|
+
(x, y) => (Math.floor(y / 2) + Math.floor(x / 3)) % 2 === 0,
|
|
169
|
+
(x, y) => ((x * y) % 2) + ((x * y) % 3) === 0,
|
|
170
|
+
(x, y) => (((x * y) % 2) + ((x * y) % 3)) % 2 === 0,
|
|
171
|
+
(x, y) => (((x + y) % 2) + ((x * y) % 3)) % 2 === 0,
|
|
172
|
+
];
|
|
173
|
+
class Grid {
|
|
174
|
+
constructor(size) {
|
|
175
|
+
this.size = size;
|
|
176
|
+
this.dark = Array.from({ length: size }, () => new Array(size).fill(false));
|
|
177
|
+
this.reserved = Array.from({ length: size }, () => new Array(size).fill(false));
|
|
178
|
+
}
|
|
179
|
+
set(x, y, dark) {
|
|
180
|
+
this.dark[y][x] = dark;
|
|
181
|
+
this.reserved[y][x] = true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function drawFunctionPatterns(grid, version) {
|
|
185
|
+
const size = grid.size;
|
|
186
|
+
// Patrones de posición (7×7) con su separador claro.
|
|
187
|
+
for (const [cx, cy] of [[3, 3], [size - 4, 3], [3, size - 4]]) {
|
|
188
|
+
for (let dy = -4; dy <= 4; dy++) {
|
|
189
|
+
for (let dx = -4; dx <= 4; dx++) {
|
|
190
|
+
const x = cx + dx;
|
|
191
|
+
const y = cy + dy;
|
|
192
|
+
if (x < 0 || y < 0 || x >= size || y >= size)
|
|
193
|
+
continue;
|
|
194
|
+
const ring = Math.max(Math.abs(dx), Math.abs(dy));
|
|
195
|
+
grid.set(x, y, ring !== 2 && ring !== 4);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Patrones de alineación (5×5), salvo los que pisan los de posición.
|
|
200
|
+
const align = alignmentPositions(version);
|
|
201
|
+
for (const cy of align) {
|
|
202
|
+
for (const cx of align) {
|
|
203
|
+
if (grid.reserved[cy][cx])
|
|
204
|
+
continue;
|
|
205
|
+
for (let dy = -2; dy <= 2; dy++) {
|
|
206
|
+
for (let dx = -2; dx <= 2; dx++)
|
|
207
|
+
grid.set(cx + dx, cy + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Líneas de temporización.
|
|
212
|
+
for (let i = 8; i < size - 8; i++) {
|
|
213
|
+
grid.set(i, 6, i % 2 === 0);
|
|
214
|
+
grid.set(6, i, i % 2 === 0);
|
|
215
|
+
}
|
|
216
|
+
// Reserva del formato (se escribe después) y módulo oscuro fijo.
|
|
217
|
+
drawFormat(grid, 0);
|
|
218
|
+
// Información de versión (v7+).
|
|
219
|
+
if (version >= 7) {
|
|
220
|
+
const bits = (version << 12) | bchRemainder(version, 0x1f25, 12);
|
|
221
|
+
for (let i = 0; i < 18; i++) {
|
|
222
|
+
const dark = ((bits >>> i) & 1) === 1;
|
|
223
|
+
const a = size - 11 + (i % 3);
|
|
224
|
+
const b = Math.floor(i / 3);
|
|
225
|
+
grid.set(a, b, dark);
|
|
226
|
+
grid.set(b, a, dark);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function drawFormat(grid, bits) {
|
|
231
|
+
const size = grid.size;
|
|
232
|
+
const bit = (i) => ((bits >>> i) & 1) === 1;
|
|
233
|
+
// Copia junto al patrón superior izquierdo.
|
|
234
|
+
for (let i = 0; i <= 5; i++)
|
|
235
|
+
grid.set(8, i, bit(i));
|
|
236
|
+
grid.set(8, 7, bit(6));
|
|
237
|
+
grid.set(8, 8, bit(7));
|
|
238
|
+
grid.set(7, 8, bit(8));
|
|
239
|
+
for (let i = 9; i < 15; i++)
|
|
240
|
+
grid.set(14 - i, 8, bit(i));
|
|
241
|
+
// Copia repartida entre los otros dos patrones.
|
|
242
|
+
for (let i = 0; i < 8; i++)
|
|
243
|
+
grid.set(size - 1 - i, 8, bit(i));
|
|
244
|
+
for (let i = 8; i < 15; i++)
|
|
245
|
+
grid.set(8, size - 15 + i, bit(i));
|
|
246
|
+
grid.set(8, size - 8, true);
|
|
247
|
+
}
|
|
248
|
+
/** Coloca los codewords en zigzag de dos columnas, de derecha a izquierda, saltando la columna 6. */
|
|
249
|
+
function drawCodewords(grid, codewords) {
|
|
250
|
+
const size = grid.size;
|
|
251
|
+
let index = 0;
|
|
252
|
+
const total = codewords.length * 8;
|
|
253
|
+
for (let right = size - 1; right >= 1; right -= 2) {
|
|
254
|
+
if (right === 6)
|
|
255
|
+
right = 5;
|
|
256
|
+
const upward = ((right + 1) & 2) === 0;
|
|
257
|
+
for (let step = 0; step < size; step++) {
|
|
258
|
+
const y = upward ? size - 1 - step : step;
|
|
259
|
+
for (let k = 0; k < 2; k++) {
|
|
260
|
+
const x = right - k;
|
|
261
|
+
if (grid.reserved[y][x])
|
|
262
|
+
continue;
|
|
263
|
+
if (index < total)
|
|
264
|
+
grid.dark[y][x] = ((codewords[index >>> 3] >>> (7 - (index & 7))) & 1) === 1;
|
|
265
|
+
index++;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function applyMask(grid, mask) {
|
|
271
|
+
const test = MASKS[mask];
|
|
272
|
+
for (let y = 0; y < grid.size; y++) {
|
|
273
|
+
for (let x = 0; x < grid.size; x++) {
|
|
274
|
+
if (!grid.reserved[y][x] && test(x, y))
|
|
275
|
+
grid.dark[y][x] = !grid.dark[y][x];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** Penalización del estándar (reglas N1–N4): menor es más legible. */
|
|
280
|
+
function penalty(dark) {
|
|
281
|
+
const size = dark.length;
|
|
282
|
+
let score = 0;
|
|
283
|
+
const lines = [];
|
|
284
|
+
for (let i = 0; i < size; i++) {
|
|
285
|
+
lines.push([...dark[i]]);
|
|
286
|
+
lines.push(dark.map((row) => row[i]));
|
|
287
|
+
}
|
|
288
|
+
// N1: rachas de 5 o más módulos iguales. N3: patrones 1:1:3:1:1 con 4 claros a un lado.
|
|
289
|
+
const finderA = [true, false, true, true, true, false, true, false, false, false, false];
|
|
290
|
+
const finderB = [...finderA].reverse();
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
let run = 1;
|
|
293
|
+
for (let i = 1; i <= size; i++) {
|
|
294
|
+
if (i < size && line[i] === line[i - 1]) {
|
|
295
|
+
run++;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
if (run >= 5)
|
|
299
|
+
score += run - 2;
|
|
300
|
+
run = 1;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const padded = [false, false, false, false, ...line, false, false, false, false];
|
|
304
|
+
for (let i = 0; i + 11 <= padded.length; i++) {
|
|
305
|
+
if (finderA.every((v, k) => padded[i + k] === v) || finderB.every((v, k) => padded[i + k] === v))
|
|
306
|
+
score += 40;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// N2: bloques 2×2 del mismo color.
|
|
310
|
+
for (let y = 0; y < size - 1; y++) {
|
|
311
|
+
for (let x = 0; x < size - 1; x++) {
|
|
312
|
+
const c = dark[y][x];
|
|
313
|
+
if (c === dark[y][x + 1] && c === dark[y + 1][x] && c === dark[y + 1][x + 1])
|
|
314
|
+
score += 3;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// N4: proporción de módulos oscuros lejos del 50 %.
|
|
318
|
+
const darkCount = dark.reduce((sum, row) => sum + row.filter(Boolean).length, 0);
|
|
319
|
+
const percent = (darkCount * 100) / (size * size);
|
|
320
|
+
score += Math.floor(Math.abs(percent - 50) / 5) * 10;
|
|
321
|
+
return score;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Codifica `text` como matriz QR. Elige el modo más compacto, la versión más
|
|
325
|
+
* pequeña que lo contiene y la máscara con menor penalización.
|
|
326
|
+
*
|
|
327
|
+
* @throws RangeError si el texto no cabe en la versión 40 con ese nivel.
|
|
328
|
+
*/
|
|
329
|
+
function cbQrEncode(text, options = {}) {
|
|
330
|
+
const ec = options.errorCorrection ?? 'M';
|
|
331
|
+
const mode = chooseMode(text);
|
|
332
|
+
const { bits: content, count } = encodeContent(text, mode);
|
|
333
|
+
let version = Math.max(1, Math.min(40, options.minVersion ?? 1));
|
|
334
|
+
for (;; version++) {
|
|
335
|
+
if (version > 40)
|
|
336
|
+
throw new RangeError(`cbQrEncode: el texto no cabe en un QR (nivel ${ec}).`);
|
|
337
|
+
const needed = 4 + countBits(mode, version) + content.bits.length;
|
|
338
|
+
if (count < 2 ** countBits(mode, version) && needed <= dataCodewords(version, ec) * 8)
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
// Segmento + terminador + relleno hasta la capacidad.
|
|
342
|
+
const buffer = new BitBuffer();
|
|
343
|
+
buffer.push(MODE_INDICATOR[mode], 4);
|
|
344
|
+
buffer.push(count, countBits(mode, version));
|
|
345
|
+
buffer.bits.push(...content.bits);
|
|
346
|
+
const capacity = dataCodewords(version, ec) * 8;
|
|
347
|
+
buffer.push(0, Math.min(4, capacity - buffer.bits.length));
|
|
348
|
+
buffer.push(0, (8 - (buffer.bits.length % 8)) % 8);
|
|
349
|
+
const data = [];
|
|
350
|
+
for (let i = 0; i < buffer.bits.length; i += 8)
|
|
351
|
+
data.push(buffer.bits.slice(i, i + 8).reduce((acc, b) => (acc << 1) | b, 0));
|
|
352
|
+
for (let pad = 0xec; data.length < capacity / 8; pad ^= 0xec ^ 0x11)
|
|
353
|
+
data.push(pad);
|
|
354
|
+
// Bloques con su corrección, intercalados.
|
|
355
|
+
const blocks = EC_BLOCKS[ec][version];
|
|
356
|
+
const ecLength = EC_CODEWORDS_PER_BLOCK[ec][version];
|
|
357
|
+
const totalCodewords = Math.floor(rawDataModules(version) / 8);
|
|
358
|
+
const shortBlocks = blocks - (totalCodewords % blocks);
|
|
359
|
+
const shortLength = Math.floor(totalCodewords / blocks) - ecLength;
|
|
360
|
+
const dataBlocks = [];
|
|
361
|
+
const ecBlocks = [];
|
|
362
|
+
for (let b = 0, offset = 0; b < blocks; b++) {
|
|
363
|
+
const length = shortLength + (b < shortBlocks ? 0 : 1);
|
|
364
|
+
const block = data.slice(offset, offset + length);
|
|
365
|
+
offset += length;
|
|
366
|
+
dataBlocks.push(block);
|
|
367
|
+
ecBlocks.push(cbQrReedSolomon(block, ecLength));
|
|
368
|
+
}
|
|
369
|
+
const codewords = [];
|
|
370
|
+
for (let i = 0; i <= shortLength; i++) {
|
|
371
|
+
for (const block of dataBlocks)
|
|
372
|
+
if (i < block.length)
|
|
373
|
+
codewords.push(block[i]);
|
|
374
|
+
}
|
|
375
|
+
for (let i = 0; i < ecLength; i++) {
|
|
376
|
+
for (const block of ecBlocks)
|
|
377
|
+
codewords.push(block[i]);
|
|
378
|
+
}
|
|
379
|
+
// Matriz con la mejor máscara.
|
|
380
|
+
const size = version * 4 + 17;
|
|
381
|
+
let best = null;
|
|
382
|
+
for (let mask = 0; mask < 8; mask++) {
|
|
383
|
+
const grid = new Grid(size);
|
|
384
|
+
drawFunctionPatterns(grid, version);
|
|
385
|
+
drawCodewords(grid, codewords);
|
|
386
|
+
applyMask(grid, mask);
|
|
387
|
+
drawFormat(grid, cbQrFormatBits(ec, mask));
|
|
388
|
+
const score = penalty(grid.dark);
|
|
389
|
+
if (!best || score < best.score)
|
|
390
|
+
best = { mask, dark: grid.dark, score };
|
|
391
|
+
}
|
|
392
|
+
return { version, size, errorCorrection: ec, mask: best.mask, modules: best.dark };
|
|
393
|
+
}
|
|
394
|
+
/** Niveles ordenados de menor a mayor corrección. */
|
|
395
|
+
const CB_QR_ERROR_CORRECTION_LEVELS = EC_ORDER;
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Código QR de CaribeNG, generado en SVG con un codificador propio (sin
|
|
399
|
+
* dependencias). Elige solo la versión y la máscara; admite color, fondo,
|
|
400
|
+
* margen y un logo centrado.
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```html
|
|
404
|
+
* <cb-qrcode value="https://caribeng.dev" [size]="180" />
|
|
405
|
+
* <cb-qrcode [value]="pago" errorCorrection="H" image="assets/logo.svg" />
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
class CbQrcode {
|
|
409
|
+
constructor() {
|
|
410
|
+
/** Textos de interfaz en el idioma activo (`provideCaribeNG({ locale })`). */
|
|
411
|
+
this.t = injectCbTranslation();
|
|
412
|
+
/** Texto o URL a codificar. */
|
|
413
|
+
this.value = input('', /* @ts-ignore */
|
|
414
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
415
|
+
/** Lado en píxeles. */
|
|
416
|
+
this.size = input(160, /* @ts-ignore */
|
|
417
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
418
|
+
/** Corrección de errores. Usa `H` si pones un logo encima. */
|
|
419
|
+
this.errorCorrection = input('M', /* @ts-ignore */
|
|
420
|
+
...(ngDevMode ? [{ debugName: "errorCorrection" }] : /* istanbul ignore next */ []));
|
|
421
|
+
/** Color de los módulos (cualquier color CSS). */
|
|
422
|
+
this.color = input('#000000', /* @ts-ignore */
|
|
423
|
+
...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
424
|
+
/** Color de fondo. Mantén buen contraste con `color` para que se pueda leer. */
|
|
425
|
+
this.background = input('#ffffff', /* @ts-ignore */
|
|
426
|
+
...(ngDevMode ? [{ debugName: "background" }] : /* istanbul ignore next */ []));
|
|
427
|
+
/** Margen claro alrededor, en módulos (el estándar pide 4). */
|
|
428
|
+
this.margin = input(4, /* @ts-ignore */
|
|
429
|
+
...(ngDevMode ? [{ debugName: "margin" }] : /* istanbul ignore next */ []));
|
|
430
|
+
/** Logo centrado (URL). Ocupa ~20 % del lado; combínalo con `errorCorrection="H"`. */
|
|
431
|
+
this.image = input('', /* @ts-ignore */
|
|
432
|
+
...(ngDevMode ? [{ debugName: "image" }] : /* istanbul ignore next */ []));
|
|
433
|
+
/** Nombre accesible. Por defecto, "Código QR" del idioma activo. */
|
|
434
|
+
this.ariaLabel = input(undefined, /* @ts-ignore */
|
|
435
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
436
|
+
/** Matriz codificada, o `null` si el valor está vacío o no cabe en un QR. */
|
|
437
|
+
this.matrix = computed(() => {
|
|
438
|
+
const value = this.value();
|
|
439
|
+
if (!value)
|
|
440
|
+
return null;
|
|
441
|
+
try {
|
|
442
|
+
return cbQrEncode(value, { errorCorrection: this.errorCorrection() });
|
|
443
|
+
}
|
|
444
|
+
catch {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
}, /* @ts-ignore */
|
|
448
|
+
...(ngDevMode ? [{ debugName: "matrix" }] : /* istanbul ignore next */ []));
|
|
449
|
+
this.extent = computed(() => (this.matrix()?.size ?? 0) + 2 * Math.max(0, this.margin()), /* @ts-ignore */
|
|
450
|
+
...(ngDevMode ? [{ debugName: "extent" }] : /* istanbul ignore next */ []));
|
|
451
|
+
this.viewBox = computed(() => `0 0 ${this.extent()} ${this.extent()}`, /* @ts-ignore */
|
|
452
|
+
...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
|
|
453
|
+
this.label = computed(() => this.ariaLabel() ?? this.t().qrCode, /* @ts-ignore */
|
|
454
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
455
|
+
/** Módulos oscuros como un único path; une los consecutivos de cada fila. */
|
|
456
|
+
this.path = computed(() => {
|
|
457
|
+
const m = this.matrix();
|
|
458
|
+
if (!m)
|
|
459
|
+
return '';
|
|
460
|
+
const offset = Math.max(0, this.margin());
|
|
461
|
+
const parts = [];
|
|
462
|
+
m.modules.forEach((row, y) => {
|
|
463
|
+
for (let x = 0; x < m.size; x++) {
|
|
464
|
+
if (!row[x])
|
|
465
|
+
continue;
|
|
466
|
+
const start = x;
|
|
467
|
+
while (x + 1 < m.size && row[x + 1])
|
|
468
|
+
x++;
|
|
469
|
+
parts.push(`M${start + offset} ${y + offset}h${x - start + 1}v1h${-(x - start + 1)}z`);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
return parts.join('');
|
|
473
|
+
}, /* @ts-ignore */
|
|
474
|
+
...(ngDevMode ? [{ debugName: "path" }] : /* istanbul ignore next */ []));
|
|
475
|
+
/** Caja del logo (en módulos), centrada y alineada a la rejilla. */
|
|
476
|
+
this.logo = computed(() => {
|
|
477
|
+
const m = this.matrix();
|
|
478
|
+
if (!m || !this.image())
|
|
479
|
+
return null;
|
|
480
|
+
let box = Math.round(m.size * 0.22);
|
|
481
|
+
if ((m.size - box) % 2 !== 0)
|
|
482
|
+
box++;
|
|
483
|
+
return { box, pad: Math.max(0, this.margin()) + (m.size - box) / 2, inset: 0.5 };
|
|
484
|
+
}, /* @ts-ignore */
|
|
485
|
+
...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
|
|
486
|
+
}
|
|
487
|
+
/** Marcado SVG del QR, p. ej. para descargarlo (`new Blob([qr.toSvg()], { type: 'image/svg+xml' })`). */
|
|
488
|
+
toSvg() {
|
|
489
|
+
const size = this.extent();
|
|
490
|
+
if (!this.matrix())
|
|
491
|
+
return '';
|
|
492
|
+
const esc = (s) => s.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<');
|
|
493
|
+
const logo = this.logo();
|
|
494
|
+
const logoMarkup = logo
|
|
495
|
+
? `<rect x="${logo.pad}" y="${logo.pad}" width="${logo.box}" height="${logo.box}" fill="${esc(this.background())}" rx="1"/>` +
|
|
496
|
+
`<image href="${esc(this.image())}" x="${logo.pad + logo.inset}" y="${logo.pad + logo.inset}" width="${logo.box - 2 * logo.inset}" height="${logo.box - 2 * logo.inset}" preserveAspectRatio="xMidYMid meet"/>`
|
|
497
|
+
: '';
|
|
498
|
+
return (`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${this.size()}" height="${this.size()}" shape-rendering="crispEdges">` +
|
|
499
|
+
`<rect width="${size}" height="${size}" fill="${esc(this.background())}"/>` +
|
|
500
|
+
`<path d="${this.path()}" fill="${esc(this.color())}"/>` +
|
|
501
|
+
logoMarkup +
|
|
502
|
+
`</svg>`);
|
|
503
|
+
}
|
|
504
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbQrcode, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
505
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbQrcode, isStandalone: true, selector: "cb-qrcode", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, errorCorrection: { classPropertyName: "errorCorrection", publicName: "errorCorrection", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, margin: { classPropertyName: "margin", publicName: "margin", isSignal: true, isRequired: false, transformFunction: null }, image: { classPropertyName: "image", publicName: "image", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.width.px": "size()", "style.height.px": "size()" }, classAttribute: "cb-qrcode" }, ngImport: i0, template: `
|
|
506
|
+
@if (matrix(); as m) {
|
|
507
|
+
<svg
|
|
508
|
+
class="cb-qrcode__svg"
|
|
509
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
510
|
+
[attr.viewBox]="viewBox()"
|
|
511
|
+
[attr.width]="size()"
|
|
512
|
+
[attr.height]="size()"
|
|
513
|
+
shape-rendering="crispEdges"
|
|
514
|
+
role="img"
|
|
515
|
+
[attr.aria-label]="label()"
|
|
516
|
+
>
|
|
517
|
+
<rect [attr.width]="extent()" [attr.height]="extent()" [attr.fill]="background()" />
|
|
518
|
+
<path [attr.d]="path()" [attr.fill]="color()" />
|
|
519
|
+
@if (logo(); as l) {
|
|
520
|
+
<rect [attr.x]="l.pad" [attr.y]="l.pad" [attr.width]="l.box" [attr.height]="l.box" [attr.fill]="background()" rx="1" />
|
|
521
|
+
<image [attr.href]="image()" [attr.x]="l.pad + l.inset" [attr.y]="l.pad + l.inset" [attr.width]="l.box - 2 * l.inset" [attr.height]="l.box - 2 * l.inset" preserveAspectRatio="xMidYMid meet" />
|
|
522
|
+
}
|
|
523
|
+
</svg>
|
|
524
|
+
}
|
|
525
|
+
`, isInline: true, styles: [":host{display:inline-block;flex:none;line-height:0}.cb-qrcode__svg{display:block;max-width:100%;height:auto}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
526
|
+
}
|
|
527
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbQrcode, decorators: [{
|
|
528
|
+
type: Component,
|
|
529
|
+
args: [{ selector: 'cb-qrcode', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
|
|
530
|
+
class: 'cb-qrcode',
|
|
531
|
+
'[style.width.px]': 'size()',
|
|
532
|
+
'[style.height.px]': 'size()',
|
|
533
|
+
}, template: `
|
|
534
|
+
@if (matrix(); as m) {
|
|
535
|
+
<svg
|
|
536
|
+
class="cb-qrcode__svg"
|
|
537
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
538
|
+
[attr.viewBox]="viewBox()"
|
|
539
|
+
[attr.width]="size()"
|
|
540
|
+
[attr.height]="size()"
|
|
541
|
+
shape-rendering="crispEdges"
|
|
542
|
+
role="img"
|
|
543
|
+
[attr.aria-label]="label()"
|
|
544
|
+
>
|
|
545
|
+
<rect [attr.width]="extent()" [attr.height]="extent()" [attr.fill]="background()" />
|
|
546
|
+
<path [attr.d]="path()" [attr.fill]="color()" />
|
|
547
|
+
@if (logo(); as l) {
|
|
548
|
+
<rect [attr.x]="l.pad" [attr.y]="l.pad" [attr.width]="l.box" [attr.height]="l.box" [attr.fill]="background()" rx="1" />
|
|
549
|
+
<image [attr.href]="image()" [attr.x]="l.pad + l.inset" [attr.y]="l.pad + l.inset" [attr.width]="l.box - 2 * l.inset" [attr.height]="l.box - 2 * l.inset" preserveAspectRatio="xMidYMid meet" />
|
|
550
|
+
}
|
|
551
|
+
</svg>
|
|
552
|
+
}
|
|
553
|
+
`, styles: [":host{display:inline-block;flex:none;line-height:0}.cb-qrcode__svg{display:block;max-width:100%;height:auto}\n"] }]
|
|
554
|
+
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], errorCorrection: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorCorrection", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], background: [{ type: i0.Input, args: [{ isSignal: true, alias: "background", required: false }] }], margin: [{ type: i0.Input, args: [{ isSignal: true, alias: "margin", required: false }] }], image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
555
|
+
|
|
556
|
+
/*
|
|
557
|
+
* Public API Surface de @caribeng/ui/qrcode
|
|
558
|
+
*/
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Generated bundle index. Do not edit.
|
|
562
|
+
*/
|
|
563
|
+
|
|
564
|
+
export { CB_QR_ERROR_CORRECTION_LEVELS, CbQrcode, cbQrEncode, cbQrFormatBits, cbQrReedSolomon };
|
|
@@ -117,7 +117,7 @@ class CbRating {
|
|
|
117
117
|
this.changed.emit(next);
|
|
118
118
|
}
|
|
119
119
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbRating, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
120
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbRating, isStandalone: true, selector: "cb-rating", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, stars: { classPropertyName: "stars", publicName: "stars", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, host: { attributes: { "role": "slider", "aria-valuemin": "0" }, listeners: { "keydown": "onKeydown($event)", "blur": "onBlur()", "mouseleave": "hover.set(0)" }, properties: { "class.cb-is-invalid": "fieldState.invalid()", "attr.aria-invalid": "fieldState.invalid() ? 'true' : null", "attr.aria-valuemax": "stars()", "attr.aria-valuenow": "value()", "attr.aria-label": "ariaLabel() || null", "attr.aria-disabled": "isDisabled() ? \"true\" : null", "attr.tabindex": "isDisabled() || readonly() ? null : 0", "class.cb-is-disabled": "isDisabled()", "class.cb-is-readonly": "readonly()" }, classAttribute: "cb-rating" }, providers: [
|
|
120
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbRating, isStandalone: true, selector: "cb-rating", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, stars: { classPropertyName: "stars", publicName: "stars", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, host: { attributes: { "role": "slider", "aria-valuemin": "0" }, listeners: { "keydown": "onKeydown($event)", "blur": "onBlur()", "mouseleave": "hover.set(0)" }, properties: { "class.cb-is-invalid": "fieldState.invalid()", "attr.aria-invalid": "fieldState.invalid() ? 'true' : null", "attr.aria-valuemax": "stars()", "attr.aria-valuenow": "value()", "attr.aria-valuetext": "fmt(t().ratingOf, value(), stars())", "attr.aria-label": "ariaLabel() || null", "attr.aria-disabled": "isDisabled() ? \"true\" : null", "attr.tabindex": "isDisabled() || readonly() ? null : 0", "class.cb-is-disabled": "isDisabled()", "class.cb-is-readonly": "readonly()" }, classAttribute: "cb-rating" }, providers: [
|
|
121
121
|
{
|
|
122
122
|
provide: NG_VALUE_ACCESSOR,
|
|
123
123
|
useExisting: forwardRef(() => CbRating),
|
|
@@ -125,19 +125,17 @@ class CbRating {
|
|
|
125
125
|
},
|
|
126
126
|
], ngImport: i0, template: `
|
|
127
127
|
@for (i of starList(); track i) {
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
<!-- Las estrellas son decorativas: el control accesible es el propio slider (sin controles anidados). -->
|
|
129
|
+
<span
|
|
130
130
|
class="cb-rating__star"
|
|
131
131
|
[class]="'cb-rating__star--' + size()"
|
|
132
132
|
[class.cb-rating__star--on]="i <= display()"
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
[disabled]="isDisabled() || readonly()"
|
|
136
|
-
(click)="pick(i)"
|
|
133
|
+
aria-hidden="true"
|
|
134
|
+
(click)="isDisabled() || readonly() || pick(i)"
|
|
137
135
|
(mouseenter)="hover.set(i)"
|
|
138
136
|
>
|
|
139
|
-
<cb-icon name="star" [size]="iconPx()"
|
|
140
|
-
</
|
|
137
|
+
<cb-icon name="star" [size]="iconPx()" />
|
|
138
|
+
</span>
|
|
141
139
|
}
|
|
142
140
|
`, isInline: true, styles: [":host{display:inline-flex;align-items:center;gap:var(--cb-space-1);border-radius:var(--cb-radius-sm);outline:none}:host:focus-visible{box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-rating__star{display:inline-flex;padding:2px;border:none;background:transparent;color:var(--cb-color-surface-300);cursor:pointer;transition:color var(--cb-duration-fast) var(--cb-ease),transform var(--cb-duration-fast) var(--cb-ease)}.cb-rating__star:hover{transform:scale(1.1)}.cb-rating__star--on{color:var(--cb-color-warning-400)}:host(.cb-is-readonly) .cb-rating__star,:host(.cb-is-disabled) .cb-rating__star{cursor:default}:host(.cb-is-readonly) .cb-rating__star:hover,:host(.cb-is-disabled) .cb-rating__star:hover{transform:none}:host(.cb-is-disabled){opacity:var(--cb-opacity-disabled, .55)}:host-context([data-theme=\"dark\"]) .cb-rating__star{color:var(--cb-color-surface-500)}:host-context([data-theme=\"dark\"]) .cb-rating__star--on{color:var(--cb-color-warning-400)}:host(.cb-is-invalid) .cb-rating__star:not(.cb-rating__star--on){color:var(--cb-color-danger)}\n"], dependencies: [{ kind: "component", type: CbIcon, selector: "cb-icon", inputs: ["name", "size", "spin", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
143
141
|
}
|
|
@@ -151,6 +149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
151
149
|
'aria-valuemin': '0',
|
|
152
150
|
'[attr.aria-valuemax]': 'stars()',
|
|
153
151
|
'[attr.aria-valuenow]': 'value()',
|
|
152
|
+
'[attr.aria-valuetext]': 'fmt(t().ratingOf, value(), stars())',
|
|
154
153
|
'[attr.aria-label]': 'ariaLabel() || null',
|
|
155
154
|
'[attr.aria-disabled]': 'isDisabled() ? "true" : null',
|
|
156
155
|
'[attr.tabindex]': 'isDisabled() || readonly() ? null : 0',
|
|
@@ -161,19 +160,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
|
|
|
161
160
|
'(mouseleave)': 'hover.set(0)',
|
|
162
161
|
}, template: `
|
|
163
162
|
@for (i of starList(); track i) {
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
<!-- Las estrellas son decorativas: el control accesible es el propio slider (sin controles anidados). -->
|
|
164
|
+
<span
|
|
166
165
|
class="cb-rating__star"
|
|
167
166
|
[class]="'cb-rating__star--' + size()"
|
|
168
167
|
[class.cb-rating__star--on]="i <= display()"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
[disabled]="isDisabled() || readonly()"
|
|
172
|
-
(click)="pick(i)"
|
|
168
|
+
aria-hidden="true"
|
|
169
|
+
(click)="isDisabled() || readonly() || pick(i)"
|
|
173
170
|
(mouseenter)="hover.set(i)"
|
|
174
171
|
>
|
|
175
|
-
<cb-icon name="star" [size]="iconPx()"
|
|
176
|
-
</
|
|
172
|
+
<cb-icon name="star" [size]="iconPx()" />
|
|
173
|
+
</span>
|
|
177
174
|
}
|
|
178
175
|
`, providers: [
|
|
179
176
|
{
|