@livenetworks/ashlar 1.6.1 → 2.0.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/LICENSE +641 -0
- package/README.md +202 -86
- package/{js → components}/COMPONENTS.md +1116 -1108
- package/{js → components}/index.js +81 -58
- package/{js → components}/ln-accordion/README.md +7 -6
- package/components/ln-accordion/ln-accordion-dev.scss +8 -0
- package/components/ln-accordion/ln-accordion.js +1 -0
- package/components/ln-accordion/ln-accordion.schema.json +30 -0
- package/components/ln-accordion/ln-accordion.scss +8 -0
- package/{js → components}/ln-accordion/src/ln-accordion.js +8 -2
- package/{js → components}/ln-ajax/README.md +171 -160
- package/components/ln-ajax/ln-ajax-dev.scss +8 -0
- package/components/ln-ajax/ln-ajax.js +1 -0
- package/components/ln-ajax/ln-ajax.schema.json +30 -0
- package/{js → components}/ln-ajax/src/ln-ajax.js +65 -30
- package/{js → components}/ln-api-connector/README.md +27 -5
- package/components/ln-api-connector/ln-api-connector.js +1 -0
- package/components/ln-api-connector/ln-api-connector.schema.json +96 -0
- package/components/ln-api-connector/src/connector-core.js +97 -0
- package/components/ln-api-connector/src/ln-api-connector.js +447 -0
- package/{js → components}/ln-api-queue/README.md +12 -9
- package/components/ln-api-queue/ln-api-queue.js +1 -0
- package/components/ln-api-queue/ln-api-queue.schema.json +34 -0
- package/{js → components}/ln-api-queue/src/ln-api-queue.js +33 -14
- package/{js → components}/ln-api-queue/src/queue-storage.js +7 -3
- package/{js → components}/ln-autoresize/README.md +129 -127
- package/components/ln-autoresize/ln-autoresize-dev.scss +8 -0
- package/components/ln-autoresize/ln-autoresize.js +1 -0
- package/components/ln-autoresize/ln-autoresize.schema.json +22 -0
- package/{js → components}/ln-autoresize/src/ln-autoresize.js +8 -1
- package/{js → components}/ln-autosave/README.md +127 -124
- package/components/ln-autosave/ln-autosave-dev.scss +13 -0
- package/components/ln-autosave/ln-autosave.js +1 -0
- package/components/ln-autosave/ln-autosave.schema.json +48 -0
- package/components/ln-autosave/src/autosave-model.js +34 -0
- package/{js → components}/ln-autosave/src/ln-autosave.js +65 -58
- package/components/ln-chart/README.md +145 -0
- package/components/ln-chart/ln-chart-dev.scss +20 -0
- package/components/ln-chart/ln-chart.js +1 -0
- package/components/ln-chart/ln-chart.schema.json +146 -0
- package/components/ln-chart/ln-chart.scss +8 -0
- package/components/ln-chart/src/chart-model.js +154 -0
- package/components/ln-chart/src/ln-chart.js +176 -0
- package/{js → components}/ln-circular-progress/README.md +15 -14
- package/components/ln-circular-progress/ln-circular-progress-dev.scss +8 -0
- package/components/ln-circular-progress/ln-circular-progress.js +1 -0
- package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -0
- package/{js → components}/ln-circular-progress/src/ln-circular-progress.js +32 -50
- package/{js → components}/ln-confirm/README.md +69 -18
- package/components/ln-confirm/ln-confirm-dev.scss +24 -0
- package/components/ln-confirm/ln-confirm.js +1 -0
- package/components/ln-confirm/ln-confirm.schema.json +66 -0
- package/components/ln-confirm/ln-confirm.scss +24 -0
- package/{js → components}/ln-confirm/src/ln-confirm.js +180 -171
- package/{js → components}/ln-core/README.md +374 -149
- package/components/ln-core/attrs.js +273 -0
- package/components/ln-core/compare.js +40 -0
- package/components/ln-core/crypto.js +265 -0
- package/components/ln-core/date.js +50 -0
- package/components/ln-core/dom.js +115 -0
- package/components/ln-core/events.js +122 -0
- package/components/ln-core/form.js +136 -0
- package/{js → components}/ln-core/hash.js +149 -92
- package/components/ln-core/helpers.js +33 -0
- package/components/ln-core/http.js +48 -0
- package/components/ln-core/index.js +11 -0
- package/components/ln-core/lifecycle.js +403 -0
- package/components/ln-core/ln-core.schema.json +109 -0
- package/components/ln-core/locale.js +55 -0
- package/components/ln-core/matching.js +78 -0
- package/components/ln-core/number.js +125 -0
- package/components/ln-core/progress.js +30 -0
- package/components/ln-core/template.js +206 -0
- package/{js → components}/ln-core/window-cache.js +247 -213
- package/{js → components}/ln-couchdb-connector/README.md +7 -5
- package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
- package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -0
- package/{js → components}/ln-couchdb-connector/src/ln-couchdb-connector.js +29 -43
- package/{js → components}/ln-data-coordinator/README.md +109 -73
- package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -0
- package/components/ln-data-coordinator/ln-data-coordinator.js +1 -0
- package/components/ln-data-coordinator/ln-data-coordinator.schema.json +196 -0
- package/components/ln-data-coordinator/src/data-read-policy.js +41 -0
- package/{js → components}/ln-data-coordinator/src/ln-data-coordinator.js +411 -154
- package/{js → components}/ln-data-coordinator/src/mutation-receipts.js +0 -5
- package/{js → components}/ln-data-store/README.md +42 -17
- package/components/ln-data-store/ln-data-store-dev.scss +13 -0
- package/components/ln-data-store/ln-data-store.js +1 -0
- package/components/ln-data-store/ln-data-store.schema.json +84 -0
- package/components/ln-data-store/src/data-store-model.js +155 -0
- package/{js → components}/ln-data-store/src/ln-data-store.js +407 -105
- package/components/ln-data-store/src/window-index.js +119 -0
- package/{js → components}/ln-date/README.md +17 -7
- package/{js → components}/ln-date/ln-date-dev.scss +14 -14
- package/components/ln-date/ln-date.js +1 -0
- package/components/ln-date/ln-date.schema.json +92 -0
- package/components/ln-date/src/date-model.js +186 -0
- package/components/ln-date/src/ln-date.js +486 -0
- package/components/ln-debug/README.md +132 -0
- package/components/ln-debug/ln-debug.js +1 -0
- package/components/ln-debug/ln-debug.schema.json +28 -0
- package/components/ln-debug/src/console-sink.js +19 -0
- package/components/ln-debug/src/debug-verifier.js +331 -0
- package/components/ln-debug/src/gate.js +95 -0
- package/components/ln-debug/src/generated-attributes.js +299 -0
- package/components/ln-debug/src/ln-debug.js +60 -0
- package/{js → components}/ln-dropdown/README.md +150 -140
- package/components/ln-dropdown/ln-dropdown-dev.scss +13 -0
- package/components/ln-dropdown/ln-dropdown.js +1 -0
- package/components/ln-dropdown/ln-dropdown.schema.json +90 -0
- package/components/ln-dropdown/ln-dropdown.scss +18 -0
- package/{js → components}/ln-dropdown/src/ln-dropdown.js +114 -11
- package/{js → components}/ln-editor/README.md +11 -9
- package/components/ln-editor/ln-editor-dev.scss +18 -0
- package/components/ln-editor/ln-editor.js +1 -0
- package/components/ln-editor/ln-editor.schema.json +58 -0
- package/components/ln-editor/ln-editor.scss +13 -0
- package/{js → components}/ln-editor/src/ln-editor.js +59 -11
- package/{js → components}/ln-external-links/README.md +10 -8
- package/components/ln-external-links/ln-external-links.js +1 -0
- package/components/ln-external-links/ln-external-links.schema.json +18 -0
- package/{js → components}/ln-external-links/src/ln-external-links.js +13 -11
- package/{js → components}/ln-fill/README.md +6 -8
- package/components/ln-fill/ln-fill.js +1 -0
- package/components/ln-fill/ln-fill.schema.json +23 -0
- package/{js → components}/ln-fill/src/ln-fill.js +7 -1
- package/components/ln-filter/README.md +131 -0
- package/components/ln-filter/ln-filter-dev.scss +13 -0
- package/components/ln-filter/ln-filter.js +1 -0
- package/components/ln-filter/ln-filter.schema.json +153 -0
- package/components/ln-filter/src/filter-model.js +185 -0
- package/components/ln-filter/src/ln-filter.js +435 -0
- package/{js → components}/ln-form/README.md +260 -264
- package/components/ln-form/ln-form-dev.scss +8 -0
- package/components/ln-form/ln-form.js +1 -0
- package/components/ln-form/ln-form.schema.json +45 -0
- package/{js → components}/ln-form/src/ln-form.js +107 -99
- package/{js → components}/ln-http/README.md +11 -6
- package/components/ln-http/ln-http.js +1 -0
- package/components/ln-http/ln-http.schema.json +6 -0
- package/components/ln-http/src/http-core.js +51 -0
- package/{js → components}/ln-http/src/ln-http.js +28 -33
- package/{js → components}/ln-icon/README.md +16 -9
- package/components/ln-icon/ln-icon.schema.json +6 -0
- package/components/ln-include/README.md +75 -0
- package/components/ln-include/ln-include-dev.scss +13 -0
- package/components/ln-include/ln-include.js +1 -0
- package/components/ln-include/ln-include.schema.json +23 -0
- package/components/ln-include/src/ln-include.js +111 -0
- package/components/ln-key/README.md +130 -0
- package/components/ln-key/ln-key-dev.scss +18 -0
- package/components/ln-key/ln-key.js +1 -0
- package/components/ln-key/ln-key.schema.json +56 -0
- package/components/ln-key/src/key-model.js +146 -0
- package/components/ln-key/src/ln-key.js +201 -0
- package/{js → components}/ln-link/README.md +7 -9
- package/components/ln-link/ln-link-dev.scss +8 -0
- package/components/ln-link/ln-link.js +1 -0
- package/components/ln-link/ln-link.schema.json +22 -0
- package/{js → components}/ln-link/src/ln-link.js +16 -11
- package/components/ln-list/README.md +152 -0
- package/components/ln-list/ln-list-dev.scss +8 -0
- package/components/ln-list/ln-list.js +1 -0
- package/components/ln-list/ln-list.schema.json +166 -0
- package/components/ln-list/ln-list.scss +25 -0
- package/{js → components}/ln-list/src/ln-list.js +1301 -1216
- package/{js → components}/ln-modal/README.md +13 -10
- package/components/ln-modal/ln-modal-dev.scss +18 -0
- package/components/ln-modal/ln-modal.js +1 -0
- package/components/ln-modal/ln-modal.schema.json +54 -0
- package/components/ln-modal/ln-modal.scss +51 -0
- package/{js → components}/ln-modal/src/ln-modal.js +164 -137
- package/{js → components}/ln-nav/README.md +11 -11
- package/components/ln-nav/ln-nav.js +1 -0
- package/components/ln-nav/ln-nav.schema.json +25 -0
- package/{js → components}/ln-nav/src/ln-nav.js +25 -14
- package/components/ln-number/README.md +205 -0
- package/{js → components}/ln-number/ln-number-dev.scss +13 -13
- package/components/ln-number/ln-number.js +1 -0
- package/components/ln-number/ln-number.schema.json +63 -0
- package/components/ln-number/src/ln-number.js +400 -0
- package/components/ln-number/src/number-model.js +31 -0
- package/components/ln-obfuscator/README.md +60 -0
- package/components/ln-obfuscator/ln-obfuscator.js +1 -0
- package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -0
- package/components/ln-obfuscator/src/ln-obfuscator.js +159 -0
- package/components/ln-obfuscator/src/obfuscator-model.js +250 -0
- package/{js → components}/ln-options/README.md +3 -1
- package/components/ln-options/ln-options-dev.scss +13 -0
- package/components/ln-options/ln-options.js +1 -0
- package/components/ln-options/ln-options.schema.json +41 -0
- package/{js → components}/ln-options/src/ln-options.js +13 -5
- package/components/ln-persist/README.md +151 -0
- package/components/ln-persist/ln-persist.js +1 -0
- package/components/ln-persist/ln-persist.schema.json +28 -0
- package/components/ln-persist/src/ln-persist.js +83 -0
- package/components/ln-picklist/README.md +230 -0
- package/components/ln-picklist/ln-picklist-dev.scss +22 -0
- package/components/ln-picklist/ln-picklist.js +1 -0
- package/components/ln-picklist/ln-picklist.schema.json +49 -0
- package/components/ln-picklist/src/ln-picklist.js +228 -0
- package/{js → components}/ln-popover/README.md +164 -162
- package/components/ln-popover/ln-popover-dev.scss +13 -0
- package/components/ln-popover/ln-popover.js +1 -0
- package/components/ln-popover/ln-popover.schema.json +82 -0
- package/components/ln-popover/ln-popover.scss +18 -0
- package/{js → components}/ln-popover/src/ln-popover.js +42 -36
- package/{js → components}/ln-progress/README.md +410 -413
- package/components/ln-progress/ln-progress-dev.scss +8 -0
- package/components/ln-progress/ln-progress.js +1 -0
- package/components/ln-progress/ln-progress.schema.json +40 -0
- package/components/ln-progress/src/ln-progress.js +91 -0
- package/components/ln-progress/src/progress-model.js +20 -0
- package/{js → components}/ln-router/README.md +443 -432
- package/components/ln-router/ln-router-dev.scss +13 -0
- package/components/ln-router/ln-router.js +1 -0
- package/components/ln-router/ln-router.schema.json +68 -0
- package/{js → components}/ln-router/src/ln-router.js +585 -539
- package/components/ln-router/src/router-model.js +50 -0
- package/components/ln-scroll/README.md +45 -0
- package/components/ln-scroll/ln-scroll.js +1 -0
- package/components/ln-scroll/ln-scroll.schema.json +85 -0
- package/components/ln-scroll/src/ln-scroll.js +150 -0
- package/components/ln-search/README.md +188 -0
- package/components/ln-search/ln-search-dev.scss +13 -0
- package/components/ln-search/ln-search.js +1 -0
- package/components/ln-search/ln-search.schema.json +103 -0
- package/components/ln-search/src/ln-search.js +330 -0
- package/{js → components}/ln-slug/README.md +6 -3
- package/components/ln-slug/ln-slug-dev.scss +18 -0
- package/components/ln-slug/ln-slug.js +1 -0
- package/components/ln-slug/ln-slug.schema.json +23 -0
- package/{js → components}/ln-slug/src/ln-slug.js +20 -13
- package/components/ln-slug/src/slug-model.js +21 -0
- package/{js → components}/ln-sort/README.md +178 -170
- package/{js → components}/ln-sort/ln-sort-dev.scss +8 -8
- package/components/ln-sort/ln-sort.js +1 -0
- package/components/ln-sort/ln-sort.schema.json +104 -0
- package/components/ln-sort/src/ln-sort.js +321 -0
- package/components/ln-sort/src/sort-model.js +117 -0
- package/{js → components}/ln-sortable/README.md +7 -11
- package/components/ln-sortable/ln-sortable-dev.scss +13 -0
- package/components/ln-sortable/ln-sortable.js +1 -0
- package/components/ln-sortable/ln-sortable.schema.json +36 -0
- package/{js → components}/ln-sortable/src/ln-sortable.js +8 -13
- package/{js → components}/ln-stat/README.md +3 -1
- package/components/ln-stat/ln-stat-dev.scss +8 -0
- package/components/ln-stat/ln-stat.js +1 -0
- package/components/ln-stat/ln-stat.schema.json +32 -0
- package/{js → components}/ln-stat/src/ln-stat.js +14 -18
- package/components/ln-stat/src/stat-model.js +28 -0
- package/{js → components}/ln-table/README.md +37 -24
- package/{js → components}/ln-table/ln-table-dev.scss +17 -17
- package/components/ln-table/ln-table.js +1 -0
- package/components/ln-table/ln-table.schema.json +211 -0
- package/components/ln-table/ln-table.scss +15 -0
- package/{js → components}/ln-table/src/ln-table.js +1365 -1493
- package/components/ln-table/src/table-model.js +98 -0
- package/components/ln-table-coordinator/README.md +61 -0
- package/components/ln-table-coordinator/ln-table-coordinator.js +1 -0
- package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -0
- package/components/ln-table-coordinator/src/ln-table-coordinator.js +193 -0
- package/{js → components}/ln-tabs/README.md +32 -14
- package/components/ln-tabs/ln-tabs-dev.scss +24 -0
- package/components/ln-tabs/ln-tabs.js +1 -0
- package/components/ln-tabs/ln-tabs.schema.json +75 -0
- package/components/ln-tabs/ln-tabs.scss +8 -0
- package/components/ln-tabs/src/ln-tabs.js +207 -0
- package/components/ln-tabs/src/tabs-model.js +82 -0
- package/{js → components}/ln-time/README.md +96 -95
- package/components/ln-time/ln-time-dev.scss +13 -0
- package/components/ln-time/ln-time.js +1 -0
- package/components/ln-time/ln-time.schema.json +38 -0
- package/{js → components}/ln-time/src/ln-time.js +206 -223
- package/components/ln-time/src/time-model.js +64 -0
- package/{js → components}/ln-toast/README.md +23 -5
- package/components/ln-toast/ln-toast-dev.scss +8 -0
- package/components/ln-toast/ln-toast.js +1 -0
- package/components/ln-toast/ln-toast.schema.json +65 -0
- package/components/ln-toast/ln-toast.scss +59 -0
- package/{js → components}/ln-toast/src/ln-toast.js +233 -232
- package/{js → components}/ln-toggle/README.md +198 -196
- package/{js → components}/ln-toggle/ln-toggle-dev.scss +13 -13
- package/components/ln-toggle/ln-toggle.js +1 -0
- package/components/ln-toggle/ln-toggle.schema.json +52 -0
- package/components/ln-toggle/ln-toggle.scss +37 -0
- package/{js → components}/ln-toggle/src/ln-toggle.js +61 -46
- package/{js → components}/ln-tooltip/README.md +6 -6
- package/{js → components}/ln-tooltip/ln-tooltip-dev.scss +9 -9
- package/components/ln-tooltip/ln-tooltip.js +1 -0
- package/components/ln-tooltip/ln-tooltip.schema.json +86 -0
- package/components/ln-tooltip/ln-tooltip.scss +9 -0
- package/{js → components}/ln-tooltip/src/ln-tooltip.js +14 -3
- package/{js → components}/ln-translations/README.md +3 -1
- package/components/ln-translations/ln-translations-dev.scss +13 -0
- package/components/ln-translations/ln-translations.js +1 -0
- package/components/ln-translations/ln-translations.schema.json +120 -0
- package/{js → components}/ln-translations/src/ln-translations.js +25 -10
- package/components/ln-ui-coordinator/README.md +101 -0
- package/components/ln-ui-coordinator/ln-ui-coordinator-dev.scss +8 -0
- package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -0
- package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +60 -0
- package/{js/ln-modal-coordinator/src/ln-modal-coordinator.js → components/ln-ui-coordinator/src/ln-ui-coordinator.js} +403 -345
- package/components/ln-upload/README.md +133 -0
- package/components/ln-upload/ln-upload-dev.scss +18 -0
- package/components/ln-upload/ln-upload.js +1 -0
- package/components/ln-upload/ln-upload.schema.json +193 -0
- package/components/ln-upload/ln-upload.scss +20 -0
- package/components/ln-upload/src/ln-upload.js +652 -0
- package/components/ln-upload/src/upload-model.js +78 -0
- package/{js → components}/ln-validate/README.md +182 -180
- package/{js → components}/ln-validate/ln-validate-dev.scss +15 -15
- package/components/ln-validate/ln-validate.js +1 -0
- package/components/ln-validate/ln-validate.schema.json +50 -0
- package/components/ln-validate/ln-validate.scss +7 -0
- package/{js → components}/ln-validate/src/ln-validate.js +23 -45
- package/components/ln-validate/src/validate-model.js +64 -0
- package/components/ln-websocket-connector/README.md +166 -0
- package/components/ln-websocket-connector/ln-websocket-connector.js +1 -0
- package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -0
- package/components/ln-websocket-connector/src/ln-websocket-connector.js +279 -0
- package/ln-ashlar.html-data.json +1796 -0
- package/package.json +84 -61
- package/{scss → theme}/base/_global.scss +1 -2
- package/{scss → theme}/base/_reset.scss +1 -1
- package/{scss → theme}/base/_typography.scss +2 -0
- package/theme/brand.css +73 -0
- package/{scss → theme}/components/_app-shell.scss +8 -0
- package/theme/components/_button.scss +24 -0
- package/theme/components/_chart.scss +5 -0
- package/theme/components/_confirm.scss +6 -0
- package/{scss → theme}/components/_date.scss +30 -22
- package/{scss → theme}/components/_dropdown.scss +6 -1
- package/theme/components/_form.scss +140 -0
- package/{scss → theme}/components/_layout.scss +6 -0
- package/{scss → theme}/components/_ln-table.scss +1 -6
- package/theme/components/_picklist.scss +3 -0
- package/{scss → theme}/components/_sort.scss +10 -10
- package/theme/components/_status-badge.scss +6 -0
- package/{scss → theme}/components/_table.scss +16 -0
- package/{scss → theme}/components/_tabs.scss +0 -4
- package/theme/components/_toast.scss +48 -0
- package/{scss → theme}/components/_toggle.scss +1 -1
- package/theme/components/_upload.scss +45 -0
- package/{scss → theme}/config/_breakpoints.scss +1 -1
- package/theme/config/_contrast.scss +128 -0
- package/{scss → theme}/config/_density.scss +191 -205
- package/theme/config/_palette.scss +274 -0
- package/theme/config/_theme.scss +293 -0
- package/{scss → theme}/config/_tokens.scss +285 -441
- package/{scss → theme}/config/mixins/_accordion.scss +1 -1
- package/{scss → theme}/config/mixins/_alert.scss +1 -0
- package/{scss → theme}/config/mixins/_app-shell.scss +4 -2
- package/{scss → theme}/config/mixins/_borders.scss +2 -0
- package/theme/config/mixins/_btn.scss +175 -0
- package/{scss → theme}/config/mixins/_card.scss +55 -46
- package/theme/config/mixins/_chart.scss +82 -0
- package/{scss → theme}/config/mixins/_collapsible.scss +2 -1
- package/{scss → theme}/config/mixins/_colors.scss +8 -14
- package/{scss → theme}/config/mixins/_diagnostics.scss +48 -48
- package/theme/config/mixins/_dropdown.scss +169 -0
- package/{scss → theme}/config/mixins/_editor.scss +0 -7
- package/{scss → theme}/config/mixins/_filter.scss +47 -47
- package/{scss → theme}/config/mixins/_footer.scss +1 -1
- package/{scss → theme}/config/mixins/_form.scss +49 -18
- package/{scss → theme}/config/mixins/_index.scss +62 -61
- package/{scss → theme}/config/mixins/_layout.scss +6 -2
- package/{scss → theme}/config/mixins/_ln-table.scss +31 -10
- package/{scss → theme}/config/mixins/_loader.scss +1 -1
- package/{scss → theme}/config/mixins/_modal.scss +145 -149
- package/{scss → theme}/config/mixins/_motion.scss +13 -0
- package/{scss → theme}/config/mixins/_nav.scss +7 -7
- package/theme/config/mixins/_picklist.scss +66 -0
- package/theme/config/mixins/_popover.scss +96 -0
- package/{scss → theme}/config/mixins/_sidebar.scss +7 -4
- package/{scss → theme}/config/mixins/_sort.scss +43 -42
- package/{scss → theme}/config/mixins/_status-badge.scss +15 -2
- package/{scss → theme}/config/mixins/_table.scss +25 -14
- package/{scss → theme}/config/mixins/_tabs.scss +1 -1
- package/{scss → theme}/config/mixins/_toast.scss +174 -179
- package/{scss → theme}/config/mixins/_tooltip.scss +2 -2
- package/{scss → theme}/config/mixins/_typography.scss +16 -5
- package/{scss → theme}/config/mixins/_upload.scss +8 -6
- package/theme/ln-ashlar-core.scss +24 -0
- package/theme/ln-ashlar-dev.scss +66 -0
- package/theme/ln-ashlar-landing.scss +56 -0
- package/{scss/ln-ashlar.scss → theme/ln-ashlar-theme.scss} +63 -69
- package/theme/ln-ashlar.scss +8 -0
- package/theme/presentation/_bento.scss +151 -0
- package/theme/presentation/_cta.scss +111 -0
- package/theme/presentation/_effects.scss +216 -0
- package/theme/presentation/_features.scss +108 -0
- package/theme/presentation/_footer.scss +129 -0
- package/theme/presentation/_hero.scss +158 -0
- package/theme/presentation/_layout.scss +170 -0
- package/theme/presentation/_navbar.scss +140 -0
- package/theme/presentation/_pricing.scss +262 -0
- package/theme/presentation/_stats.scss +87 -0
- package/theme/presentation/_testimonials.scss +124 -0
- package/theme/presentation/_tokens.scss +39 -0
- package/theme/presentation/_typography.scss +163 -0
- package/{scss → theme}/utilities/_animations.scss +38 -0
- package/{scss → theme}/utilities/_utilities.scss +6 -0
- package/web-types.json +2312 -0
- package/js/ln-accordion/ln-accordion.js +0 -1
- package/js/ln-ajax/ln-ajax.js +0 -1
- package/js/ln-api-connector/ln-api-connector.js +0 -1
- package/js/ln-api-connector/src/ln-api-connector.js +0 -368
- package/js/ln-api-queue/ln-api-queue.js +0 -1
- package/js/ln-autoresize/ln-autoresize.js +0 -1
- package/js/ln-autosave/ln-autosave.js +0 -1
- package/js/ln-circular-progress/ln-circular-progress.js +0 -1
- package/js/ln-confirm/_ln-confirm.scss +0 -24
- package/js/ln-confirm/ln-confirm.js +0 -1
- package/js/ln-core/crypto.js +0 -83
- package/js/ln-core/helpers.js +0 -788
- package/js/ln-core/index.js +0 -7
- package/js/ln-core/persist.js +0 -97
- package/js/ln-couchdb-connector/ln-couchdb-connector.js +0 -1
- package/js/ln-data-coordinator/ln-data-coordinator.js +0 -1
- package/js/ln-data-coordinator/src/data-read-policy.js +0 -18
- package/js/ln-data-store/ln-data-store.js +0 -1
- package/js/ln-date/ln-date.js +0 -1
- package/js/ln-date/src/ln-date.js +0 -603
- package/js/ln-debug/README.md +0 -58
- package/js/ln-debug/ln-debug.js +0 -1
- package/js/ln-debug/src/ln-debug.js +0 -19
- package/js/ln-dropdown/ln-dropdown.js +0 -1
- package/js/ln-dropdown/ln-dropdown.scss +0 -15
- package/js/ln-editor/ln-editor.js +0 -1
- package/js/ln-editor/ln-editor.scss +0 -43
- package/js/ln-external-links/ln-external-links.js +0 -1
- package/js/ln-fill/ln-fill.js +0 -1
- package/js/ln-filter/README.md +0 -189
- package/js/ln-filter/ln-filter-dev.scss +0 -8
- package/js/ln-filter/ln-filter.js +0 -1
- package/js/ln-filter/src/ln-filter.js +0 -419
- package/js/ln-form/ln-form.js +0 -1
- package/js/ln-http/ln-http.js +0 -1
- package/js/ln-link/ln-link.js +0 -1
- package/js/ln-list/README.md +0 -129
- package/js/ln-list/ln-list.js +0 -1
- package/js/ln-list/ln-list.scss +0 -28
- package/js/ln-modal/ln-modal-dev.scss +0 -13
- package/js/ln-modal/ln-modal.js +0 -1
- package/js/ln-modal/ln-modal.scss +0 -35
- package/js/ln-modal-coordinator/README.md +0 -99
- package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +0 -8
- package/js/ln-modal-coordinator/ln-modal-coordinator.js +0 -1
- package/js/ln-nav/ln-nav.js +0 -1
- package/js/ln-number/README.md +0 -149
- package/js/ln-number/ln-number.js +0 -1
- package/js/ln-number/src/ln-number.js +0 -443
- package/js/ln-options/ln-options.js +0 -1
- package/js/ln-popover/ln-popover.js +0 -1
- package/js/ln-progress/ln-progress.js +0 -1
- package/js/ln-progress/src/ln-progress.js +0 -98
- package/js/ln-router/ln-router.js +0 -1
- package/js/ln-search/README.md +0 -158
- package/js/ln-search/ln-search-dev.scss +0 -8
- package/js/ln-search/ln-search.js +0 -1
- package/js/ln-search/src/ln-search.js +0 -117
- package/js/ln-slug/ln-slug.js +0 -1
- package/js/ln-sort/ln-sort.js +0 -1
- package/js/ln-sort/src/ln-sort.js +0 -178
- package/js/ln-sortable/ln-sortable.js +0 -1
- package/js/ln-stat/ln-stat.js +0 -1
- package/js/ln-table/ln-table.js +0 -1
- package/js/ln-table/ln-table.scss +0 -11
- package/js/ln-table-coordinator/README.md +0 -73
- package/js/ln-table-coordinator/ln-table-coordinator.js +0 -1
- package/js/ln-table-coordinator/src/ln-table-coordinator.js +0 -160
- package/js/ln-tabs/ln-tabs-dev.scss +0 -18
- package/js/ln-tabs/ln-tabs.js +0 -1
- package/js/ln-tabs/src/ln-tabs.js +0 -188
- package/js/ln-time/ln-time.js +0 -1
- package/js/ln-toast/ln-toast.js +0 -1
- package/js/ln-toggle/ln-toggle.js +0 -1
- package/js/ln-tooltip/ln-tooltip.js +0 -1
- package/js/ln-tooltip/ln-tooltip.scss +0 -9
- package/js/ln-translations/ln-translations.js +0 -1
- package/js/ln-upload/README.md +0 -255
- package/js/ln-upload/ln-upload.js +0 -1
- package/js/ln-upload/ln-upload.scss +0 -20
- package/js/ln-upload/src/ln-upload.js +0 -423
- package/js/ln-validate/ln-validate.js +0 -1
- package/scss/components/_button.scss +0 -20
- package/scss/components/_confirm.scss +0 -5
- package/scss/components/_form.scss +0 -107
- package/scss/components/_status-badge.scss +0 -4
- package/scss/components/_toast.scss +0 -68
- package/scss/components/_upload.scss +0 -51
- package/scss/config/_theme.scss +0 -216
- package/scss/config/mixins/_btn.scss +0 -179
- package/scss/config/mixins/_confirm.scss +0 -31
- package/scss/config/mixins/_dropdown.scss +0 -141
- package/scss/config/mixins/_popover.scss +0 -64
- package/scss/ln-ashlar-dev.scss +0 -39
- /package/{js → components}/ln-core/positioning.js +0 -0
- /package/{js → components}/ln-core/reactive.js +0 -0
- /package/{js → components}/ln-filter/ln-filter.scss +0 -0
- /package/{js → components}/ln-icon/ln-icon.js +0 -0
- /package/{js → components}/ln-icon/src/ln-icon.js +0 -0
- /package/{js → components}/ln-search/ln-search.scss +0 -0
- /package/{js → components}/ln-toast/template.html +0 -0
- /package/{scss → theme}/components/_accordion.scss +0 -0
- /package/{scss → theme}/components/_ajax.scss +0 -0
- /package/{scss → theme}/components/_alert.scss +0 -0
- /package/{scss → theme}/components/_avatar.scss +0 -0
- /package/{scss → theme}/components/_breadcrumbs.scss +0 -0
- /package/{scss → theme}/components/_card.scss +0 -0
- /package/{scss → theme}/components/_chip.scss +0 -0
- /package/{scss → theme}/components/_circular-progress.scss +0 -0
- /package/{scss → theme}/components/_editor.scss +0 -0
- /package/{scss → theme}/components/_empty-state.scss +0 -0
- /package/{scss → theme}/components/_filter.scss +0 -0
- /package/{scss → theme}/components/_link.scss +0 -0
- /package/{scss → theme}/components/_loader.scss +0 -0
- /package/{scss → theme}/components/_modal.scss +0 -0
- /package/{scss → theme}/components/_nav.scss +0 -0
- /package/{scss → theme}/components/_page-header.scss +0 -0
- /package/{scss → theme}/components/_popover.scss +0 -0
- /package/{scss → theme}/components/_progress.scss +0 -0
- /package/{scss → theme}/components/_prose.scss +0 -0
- /package/{scss → theme}/components/_scrollbar.scss +0 -0
- /package/{scss → theme}/components/_sections.scss +0 -0
- /package/{scss → theme}/components/_sidebar.scss +0 -0
- /package/{scss → theme}/components/_stat-card.scss +0 -0
- /package/{scss → theme}/components/_stepper.scss +0 -0
- /package/{scss → theme}/components/_timeline.scss +0 -0
- /package/{scss → theme}/components/_tooltip.scss +0 -0
- /package/{scss → theme}/components/_translations.scss +0 -0
- /package/{scss → theme}/config/_icons.scss +0 -0
- /package/{scss → theme}/config/_mixins.scss +0 -0
- /package/{scss → theme}/config/mixins/_ajax.scss +0 -0
- /package/{scss → theme}/config/mixins/_avatar.scss +0 -0
- /package/{scss → theme}/config/mixins/_breadcrumbs.scss +0 -0
- /package/{scss → theme}/config/mixins/_breakpoints.scss +0 -0
- /package/{scss → theme}/config/mixins/_chip.scss +0 -0
- /package/{scss → theme}/config/mixins/_circular-progress.scss +0 -0
- /package/{scss → theme}/config/mixins/_display.scss +0 -0
- /package/{scss → theme}/config/mixins/_empty-state.scss +0 -0
- /package/{scss → theme}/config/mixins/_focus.scss +0 -0
- /package/{scss → theme}/config/mixins/_interaction.scss +0 -0
- /package/{scss → theme}/config/mixins/_kbd.scss +0 -0
- /package/{scss → theme}/config/mixins/_link.scss +0 -0
- /package/{scss → theme}/config/mixins/_page-header.scss +0 -0
- /package/{scss → theme}/config/mixins/_position.scss +0 -0
- /package/{scss → theme}/config/mixins/_progress.scss +0 -0
- /package/{scss → theme}/config/mixins/_prose.scss +0 -0
- /package/{scss → theme}/config/mixins/_shadows.scss +0 -0
- /package/{scss → theme}/config/mixins/_sizing.scss +0 -0
- /package/{scss → theme}/config/mixins/_spacing.scss +0 -0
- /package/{scss → theme}/config/mixins/_stat-card.scss +0 -0
- /package/{scss → theme}/config/mixins/_stepper.scss +0 -0
- /package/{scss → theme}/config/mixins/_timeline.scss +0 -0
- /package/{scss → theme}/config/mixins/_transitions.scss +0 -0
- /package/{scss → theme}/config/mixins/_translations.scss +0 -0
- /package/{scss → theme}/tabler-icons.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { dispatch, registerComponent } from '../../ln-core';
|
|
2
|
+
import { hasInitialValue, isFieldValid, resolveActiveErrorKeys } from './validate-model.js';
|
|
2
3
|
|
|
3
4
|
(function () {
|
|
4
5
|
const DOM_SELECTOR = 'data-ln-validate';
|
|
@@ -8,18 +9,15 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
8
9
|
const CSS_VALID = 'ln-validate-valid';
|
|
9
10
|
const CSS_INVALID = 'ln-validate-invalid';
|
|
10
11
|
|
|
11
|
-
const ERROR_MAP = {
|
|
12
|
-
required: 'valueMissing',
|
|
13
|
-
typeMismatch: 'typeMismatch',
|
|
14
|
-
tooShort: 'tooShort',
|
|
15
|
-
tooLong: 'tooLong',
|
|
16
|
-
patternMismatch: 'patternMismatch',
|
|
17
|
-
rangeUnderflow: 'rangeUnderflow',
|
|
18
|
-
rangeOverflow: 'rangeOverflow'
|
|
19
|
-
};
|
|
20
|
-
|
|
21
12
|
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
22
13
|
|
|
14
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
15
|
+
const ATTRIBUTES = {
|
|
16
|
+
'data-ln-validate': { type: 'marker', description: 'Activates validation on form input or field' },
|
|
17
|
+
'data-ln-validate-errors': { type: 'marker', description: 'Container element holding validation error message elements' },
|
|
18
|
+
'data-ln-validate-error': { type: 'string', description: 'Identifies error message template for a specific validation rule' }
|
|
19
|
+
};
|
|
20
|
+
|
|
23
21
|
// ─── Component ─────────────────────────────────────────────
|
|
24
22
|
|
|
25
23
|
function _component(dom) {
|
|
@@ -67,7 +65,6 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
67
65
|
if (el) el.classList.add('hidden');
|
|
68
66
|
}
|
|
69
67
|
} else {
|
|
70
|
-
// clear all custom errors
|
|
71
68
|
self._customErrors.forEach(function (err) {
|
|
72
69
|
if (parent) {
|
|
73
70
|
const el = parent.querySelector('[' + ERROR_SELECTOR + '="' + err + '"]');
|
|
@@ -76,7 +73,6 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
76
73
|
});
|
|
77
74
|
self._customErrors.clear();
|
|
78
75
|
}
|
|
79
|
-
// Re-run native validation to update visual state
|
|
80
76
|
if (self._touched) self.validate();
|
|
81
77
|
};
|
|
82
78
|
|
|
@@ -89,8 +85,6 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
89
85
|
|
|
90
86
|
const form = dom.form;
|
|
91
87
|
if (form) {
|
|
92
|
-
// One validated field is enough to own the form's gate —
|
|
93
|
-
// browser bubbles must yield to ln-validate's own error display.
|
|
94
88
|
if (!form.hasAttribute('novalidate')) {
|
|
95
89
|
form.setAttribute('novalidate', '');
|
|
96
90
|
}
|
|
@@ -108,16 +102,6 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
108
102
|
form.addEventListener('reset', this._onFormReset);
|
|
109
103
|
form.addEventListener('ln-validate:request-validate', this._onValidateRequest);
|
|
110
104
|
|
|
111
|
-
// Submit gate — attached once per form, by whichever validated
|
|
112
|
-
// field initializes first (marker lives on the form itself,
|
|
113
|
-
// same one-shot-guard shape as ln-fill's _fillBound). Runs on
|
|
114
|
-
// every method, GET included — this is a straight replacement
|
|
115
|
-
// for the native browser validation `novalidate` just silenced
|
|
116
|
-
// above, and native validation never had a method condition
|
|
117
|
-
// either. ln-data-coordinator's own POST/PUT/PATCH method gate
|
|
118
|
-
// for the write pipeline is a separate, later decision — it
|
|
119
|
-
// reads e.defaultPrevented first, so it never claims a submit
|
|
120
|
-
// this gate already blocked.
|
|
121
105
|
if (!form._lnValidateGateBound) {
|
|
122
106
|
form._lnValidateGateBound = true;
|
|
123
107
|
form.addEventListener('submit', function (e) {
|
|
@@ -131,23 +115,24 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
131
115
|
});
|
|
132
116
|
validationDetail.invalidFields[0].focus();
|
|
133
117
|
}
|
|
134
|
-
// Valid — nothing left to do. Native submit continues;
|
|
135
|
-
// ln-data-coordinator (document, bubble phase) or plain
|
|
136
|
-
// HTML/ln-ajax decides what happens to it next.
|
|
137
118
|
});
|
|
138
119
|
}
|
|
139
120
|
}
|
|
140
121
|
|
|
122
|
+
if (hasInitialValue(dom)) {
|
|
123
|
+
this._touched = true;
|
|
124
|
+
this.validate();
|
|
125
|
+
}
|
|
126
|
+
|
|
141
127
|
return this;
|
|
142
128
|
}
|
|
143
129
|
|
|
144
130
|
_component.prototype.validate = function () {
|
|
145
131
|
const dom = this.dom;
|
|
146
132
|
const validity = dom.validity;
|
|
147
|
-
const
|
|
148
|
-
const
|
|
133
|
+
const isValid = isFieldValid(validity, this._customErrors.size);
|
|
134
|
+
const activeErrors = resolveActiveErrorKeys(validity, this._customErrors);
|
|
149
135
|
|
|
150
|
-
// Show/hide error messages
|
|
151
136
|
const parent = dom.closest('.form-element');
|
|
152
137
|
if (parent) {
|
|
153
138
|
const errorList = parent.querySelector('[' + ERRORS_SELECTOR + ']');
|
|
@@ -155,27 +140,17 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
155
140
|
const items = errorList.querySelectorAll('[' + ERROR_SELECTOR + ']');
|
|
156
141
|
for (let i = 0; i < items.length; i++) {
|
|
157
142
|
const errorKey = items[i].getAttribute(ERROR_SELECTOR);
|
|
158
|
-
|
|
159
|
-
if (!validityProp) continue; // custom error — managed by set-custom/clear-custom
|
|
160
|
-
if (validity[validityProp]) {
|
|
161
|
-
items[i].classList.remove('hidden');
|
|
162
|
-
} else {
|
|
163
|
-
items[i].classList.add('hidden');
|
|
164
|
-
}
|
|
143
|
+
items[i].classList.toggle('hidden', !activeErrors.includes(errorKey));
|
|
165
144
|
}
|
|
166
145
|
}
|
|
167
146
|
}
|
|
168
147
|
|
|
169
|
-
// Toggle CSS classes on input
|
|
170
148
|
dom.classList.toggle(CSS_VALID, isValid);
|
|
171
149
|
dom.classList.toggle(CSS_INVALID, !isValid);
|
|
172
|
-
|
|
173
|
-
// Manage ARIA invalid attribute
|
|
174
150
|
dom.setAttribute('aria-invalid', isValid ? 'false' : 'true');
|
|
175
151
|
|
|
176
|
-
// Emit event
|
|
177
152
|
const eventName = isValid ? 'ln-validate:valid' : 'ln-validate:invalid';
|
|
178
|
-
dispatch(dom, eventName, { target: dom, field: dom.name });
|
|
153
|
+
dispatch(dom, eventName, { target: dom, field: dom.name, errors: activeErrors });
|
|
179
154
|
|
|
180
155
|
return isValid;
|
|
181
156
|
};
|
|
@@ -196,7 +171,9 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
196
171
|
};
|
|
197
172
|
|
|
198
173
|
Object.defineProperty(_component.prototype, 'isValid', {
|
|
199
|
-
get: function () {
|
|
174
|
+
get: function () {
|
|
175
|
+
return isFieldValid(this.dom.validity, this._customErrors.size);
|
|
176
|
+
}
|
|
200
177
|
});
|
|
201
178
|
|
|
202
179
|
_component.prototype.destroy = function () {
|
|
@@ -214,11 +191,12 @@ import { dispatch, registerComponent } from '../../ln-core';
|
|
|
214
191
|
|
|
215
192
|
this.dom.classList.remove(CSS_VALID, CSS_INVALID);
|
|
216
193
|
this.dom.removeAttribute('aria-invalid');
|
|
217
|
-
dispatch(this.dom, 'ln-validate:destroyed', { target: this.dom });
|
|
218
194
|
delete this.dom[DOM_ATTRIBUTE];
|
|
219
195
|
};
|
|
220
196
|
|
|
221
197
|
// ─── Init ──────────────────────────────────────────────────
|
|
222
198
|
|
|
223
|
-
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-validate'
|
|
199
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-validate', {
|
|
200
|
+
attributes: ATTRIBUTES
|
|
201
|
+
});
|
|
224
202
|
})();
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export const ERROR_MAP = {
|
|
2
|
+
required: 'valueMissing',
|
|
3
|
+
typeMismatch: 'typeMismatch',
|
|
4
|
+
tooShort: 'tooShort',
|
|
5
|
+
tooLong: 'tooLong',
|
|
6
|
+
patternMismatch: 'patternMismatch',
|
|
7
|
+
rangeUnderflow: 'rangeUnderflow',
|
|
8
|
+
rangeOverflow: 'rangeOverflow'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a field is valid given its native validity state and custom errors count.
|
|
13
|
+
* @param {{ valid?: boolean } | null | undefined} validityState
|
|
14
|
+
* @param {number} [customErrorsCount=0]
|
|
15
|
+
* @returns {boolean}
|
|
16
|
+
*/
|
|
17
|
+
export function isFieldValid(validityState, customErrorsCount = 0) {
|
|
18
|
+
if (!validityState) return customErrorsCount === 0;
|
|
19
|
+
return Boolean(validityState.valid && customErrorsCount === 0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether a field already holds a value at init, so it is validated up front.
|
|
24
|
+
* A checkbox or radio always carries a `value` ("on" by default) — only its
|
|
25
|
+
* `checked` state says whether anything was chosen.
|
|
26
|
+
* @param {{ type?: string, value?: string, checked?: boolean }} field
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
export function hasInitialValue(field) {
|
|
30
|
+
if (field.type === 'checkbox' || field.type === 'radio') return Boolean(field.checked);
|
|
31
|
+
return Boolean(field.value && field.value.trim() !== '');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolves all active error keys for a given validity state and custom errors set.
|
|
36
|
+
* @param {Record<string, boolean>} validityState
|
|
37
|
+
* @param {Set<string>|Array<string>} [customErrors]
|
|
38
|
+
* @returns {string[]}
|
|
39
|
+
*/
|
|
40
|
+
export function resolveActiveErrorKeys(validityState, customErrors) {
|
|
41
|
+
const active = [];
|
|
42
|
+
|
|
43
|
+
if (validityState) {
|
|
44
|
+
const keys = Object.keys(ERROR_MAP);
|
|
45
|
+
for (let i = 0; i < keys.length; i++) {
|
|
46
|
+
const errorKey = keys[i];
|
|
47
|
+
const prop = ERROR_MAP[errorKey];
|
|
48
|
+
if (validityState[prop]) {
|
|
49
|
+
active.push(errorKey);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (customErrors) {
|
|
55
|
+
const customList = Array.from(customErrors);
|
|
56
|
+
for (let i = 0; i < customList.length; i++) {
|
|
57
|
+
if (customList[i] && active.indexOf(customList[i]) === -1) {
|
|
58
|
+
active.push(customList[i]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return active;
|
|
64
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# `data-ln-websocket-connector`
|
|
2
|
+
|
|
3
|
+
> Applied to an element inside a `ln-data-coordinator`. Opens a WebSocket, turns server pushes into
|
|
4
|
+
> `ln-websocket-connector:fetched`, and answers the same request events as `ln-api-connector` and
|
|
5
|
+
> `ln-couchdb-connector`. Connection status is private state announced by events — never an attribute.
|
|
6
|
+
|
|
7
|
+
A zero-dependency push transport. Beside a REST connector it only delivers live changes; on its own
|
|
8
|
+
it carries reads, writes and pushes over one socket.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Declarative DOM Setup
|
|
13
|
+
|
|
14
|
+
### Live changes beside REST
|
|
15
|
+
|
|
16
|
+
The REST connector takes every request; the socket only pushes changes into the store.
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<ul data-ln-data-coordinator="tasks" hidden>
|
|
20
|
+
<li data-ln-data-store="tasks" id="tasks"></li>
|
|
21
|
+
<li data-ln-api-connector data-ln-api-base-url="https://api.example.com" data-ln-api-path="tasks"></li>
|
|
22
|
+
<li data-ln-websocket-connector data-ln-websocket-connector-url="wss://api.example.com/live"></li>
|
|
23
|
+
</ul>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Socket alone
|
|
27
|
+
|
|
28
|
+
With no REST or CouchDB connector in the coordinator, the socket takes every request too.
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<ul data-ln-data-coordinator="tasks" hidden>
|
|
32
|
+
<li data-ln-data-store="tasks" id="tasks"></li>
|
|
33
|
+
<li data-ln-websocket-connector data-ln-websocket-connector-url="wss://api.example.com/live"></li>
|
|
34
|
+
</ul>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Attributes
|
|
40
|
+
|
|
41
|
+
Both attributes are commands set from outside; the component obeys them.
|
|
42
|
+
|
|
43
|
+
| Attribute | Values | Default | Description |
|
|
44
|
+
|-----------|--------|---------|-------------|
|
|
45
|
+
| `data-ln-websocket-connector` | `connect` \| `disconnect` | `connect` | Opens or closes the socket. A bare attribute connects. |
|
|
46
|
+
| `data-ln-websocket-connector-url` | `ws://…` \| `wss://…` | — | Endpoint. Changing it while connected closes and reopens on the new URL. |
|
|
47
|
+
|
|
48
|
+
There is no attribute for the connection status. `connecting`, `connected` and `disconnected` are
|
|
49
|
+
what the component observes, not something anyone can set — writing `connected` into an attribute
|
|
50
|
+
would not connect anything. The status is announced by events; whoever listens decides how to show it.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## DOM Events
|
|
55
|
+
|
|
56
|
+
### Commands (dispatched TO the connector)
|
|
57
|
+
|
|
58
|
+
Only the `ln-websocket-connector:*` namespace is handled.
|
|
59
|
+
|
|
60
|
+
| Event | `detail` | Description |
|
|
61
|
+
|-------|----------|-------------|
|
|
62
|
+
| `ln-websocket-connector:request-sync` | `{ since, meta? }` | Delta sync since a token. |
|
|
63
|
+
| `ln-websocket-connector:request-query` | `{ query, meta? }` | One page of a query (`search`, `filters`, `sort`, `offset`, `limit`). |
|
|
64
|
+
| `ln-websocket-connector:request-create` | `{ data, tempId?, idempotencyKey?, meta? }` | Create a record. |
|
|
65
|
+
| `ln-websocket-connector:request-update` | `{ id, data, expected_version?, idempotencyKey?, meta? }` | Update a record. |
|
|
66
|
+
| `ln-websocket-connector:request-delete` | `{ id, idempotencyKey?, meta? }` | Delete a record. |
|
|
67
|
+
| `ln-websocket-connector:request-bulk-delete` | `{ ids, idempotencyKey?, meta? }` | Delete several records. |
|
|
68
|
+
|
|
69
|
+
### Notifications (emitted BY the connector)
|
|
70
|
+
|
|
71
|
+
| Event | `detail` | Description |
|
|
72
|
+
|-------|----------|-------------|
|
|
73
|
+
| `ln-websocket-connector:connecting` | `{ url, attempt }` | A connection attempt starts. `attempt` counts from 1 and resets on open. |
|
|
74
|
+
| `ln-websocket-connector:connected` | `{ url }` | The socket is open. |
|
|
75
|
+
| `ln-websocket-connector:disconnected` | `{ url, code, reason, willReconnect }` | The socket closed, or a pending reconnect was cancelled. |
|
|
76
|
+
| `ln-websocket-connector:fetched` | `{ data, since, meta }` / `{ data, total, filtered, offset, queryGen, meta }` | A sync reply, a query page, or a server push (`meta: null`). |
|
|
77
|
+
| `ln-websocket-connector:created` | `{ record, tempId, message, meta }` | Create confirmed. |
|
|
78
|
+
| `ln-websocket-connector:updated` | `{ record, id, message, meta }` | Update confirmed. |
|
|
79
|
+
| `ln-websocket-connector:deleted` | `{ response, id, message, meta }` | Delete confirmed. |
|
|
80
|
+
| `ln-websocket-connector:bulk-deleted` | `{ response, ids, message, meta }` | Bulk delete confirmed. |
|
|
81
|
+
| `ln-websocket-connector:error` | `{ action, error, status, data, conflictData, meta, … }` | A rejected request, or one that could not be delivered (`status: 0`). |
|
|
82
|
+
|
|
83
|
+
`meta` is echoed unchanged and never leaves the page.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Wire Protocol
|
|
88
|
+
|
|
89
|
+
JSON text frames.
|
|
90
|
+
|
|
91
|
+
**Request** — `{ "ref": "<string>", "type": "<type>", ...payload }`
|
|
92
|
+
|
|
93
|
+
| `type` | payload |
|
|
94
|
+
|--------|---------|
|
|
95
|
+
| `sync` | `since` |
|
|
96
|
+
| `query` | `query` |
|
|
97
|
+
| `create` | `data`, `idempotencyKey` |
|
|
98
|
+
| `update` | `id`, `data`, `expected_version`, `idempotencyKey` |
|
|
99
|
+
| `delete` | `id`, `idempotencyKey` |
|
|
100
|
+
| `bulk-delete` | `ids`, `idempotencyKey` |
|
|
101
|
+
|
|
102
|
+
**Reply** — the same `ref`, then either `{ "ok": true, "content": …, "message": … }` or
|
|
103
|
+
`{ "ok": false, "status": 409, "error": "…", "data": … }`. `content` is `{ data, deleted, synced_at }`
|
|
104
|
+
for `sync`, `{ data, total, filtered }` for `query`, the record for `create` / `update`, and the
|
|
105
|
+
server response for `delete` / `bulk-delete`. `message` is the same opaque toast payload as the REST
|
|
106
|
+
`{ message, content }` envelope.
|
|
107
|
+
|
|
108
|
+
**Push** — no `ref`: `{ "type": "changes", "data": [...], "deleted": [...], "synced_at": … }`.
|
|
109
|
+
|
|
110
|
+
`synced_at` is the same token the REST delta takes as `since`. Beside REST, a push advances the
|
|
111
|
+
store's `lastSyncedAt`, and the next REST sync sends it — the server must keep both in one currency.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Coordinator Integration
|
|
116
|
+
|
|
117
|
+
`ln-data-coordinator` needs no wiring:
|
|
118
|
+
|
|
119
|
+
- **Request connector:** `[data-ln-api-connector]` or `[data-ln-couchdb-connector]` when present,
|
|
120
|
+
otherwise `[data-ln-websocket-connector]`.
|
|
121
|
+
- **Pushes:** `:fetched` without `meta.kind` goes to `store.applySync` — upsert plus delete, the path
|
|
122
|
+
CouchDB sync already uses. Bound tables and lists refresh on `ln-data-store:synced`.
|
|
123
|
+
- **Catch-up:** on every `:connected` the coordinator runs `store.forceSync()`, a delta since
|
|
124
|
+
`lastSyncedAt`, over whichever connector takes requests.
|
|
125
|
+
|
|
126
|
+
### Showing the status
|
|
127
|
+
|
|
128
|
+
The coordinator does not render connection status. Page wiring listens and draws it — here with
|
|
129
|
+
an app-owned `data-status`, since app state stays out of `data-ln-*`:
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
const chip = document.getElementById('tasks-status');
|
|
133
|
+
['connecting', 'connected', 'disconnected'].forEach(function (status) {
|
|
134
|
+
coordinatorEl.addEventListener('ln-websocket-connector:' + status, function () {
|
|
135
|
+
chip.setAttribute('data-status', status);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 🔧 Internals
|
|
143
|
+
|
|
144
|
+
Source: `components/ln-websocket-connector/src/ln-websocket-connector.js`.
|
|
145
|
+
|
|
146
|
+
### Requests while not connected
|
|
147
|
+
|
|
148
|
+
- **Command `connect`, socket not open** (first connect, or between reconnect attempts): the request
|
|
149
|
+
is held and sent in order on open. `:connected` is dispatched before the flush, so the coordinator's
|
|
150
|
+
catch-up sync sees the store already syncing and does not send a second one.
|
|
151
|
+
- **Command `disconnect`:** the request fails at once with `:error { status: 0 }`.
|
|
152
|
+
- **Socket closes with replies outstanding:** each one fails with `:error { status: 0 }`. The
|
|
153
|
+
coordinator treats status 0 as transient and never deletes local data on it.
|
|
154
|
+
|
|
155
|
+
### Reconnect
|
|
156
|
+
|
|
157
|
+
An unexpected close while the command is `connect` retries after 1 s, doubling up to 30 s, and the
|
|
158
|
+
counter resets on a successful open. `new WebSocket()` throwing synchronously (an invalid URL, or
|
|
159
|
+
`ws://` blocked on an `https://` page) is not retried: retrying cannot fix it. The component reports
|
|
160
|
+
`:disconnected { willReconnect: false }`; a new URL or a new `connect` command opens again.
|
|
161
|
+
|
|
162
|
+
### Teardown
|
|
163
|
+
|
|
164
|
+
`destroy()` closes the socket, clears the reconnect timer, removes the request listeners and
|
|
165
|
+
deletes the instance. It dispatches nothing, so held and outstanding requests are discarded, not
|
|
166
|
+
failed.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";function I(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function k(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){o=t[r];break}if(!k(o))return}e.apply(console,t)}}function b(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function C(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){C(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const $={};function H(e,t){$[e]=t}function U(e){return $[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=H,window.lnCore.getDataMapper=U);function J(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,C(function(){new MutationObserver(function(){b(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const N={};function P(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];N[n]=t}function Q(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return N[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=P,window.lnCore.getLocaleFallback=Q,window.lnCore.ensureLocaleObserver=J);const A={};function G(e,t){A[e]||(A[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=A[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function D(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++){const a=n[l],d=a.getAttribute("data-ln-field");t[d]!=null&&(a.textContent=t[d])}const o=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<o.length;l++){const a=o[l],d=a.getAttribute("data-ln-attr").split(",");for(let h=0;h<d.length;h++){const u=d[h].trim().split(":");if(u.length!==2)continue;const i=u[0].trim(),c=u[1].trim();t[c]!=null&&a.setAttribute(i,t[c])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const a=r[l],d=a.getAttribute("data-ln-show");d in t&&a.classList.toggle("hidden",!t[d])}const s=e.querySelectorAll("[data-ln-class]");for(let l=0;l<s.length;l++){const a=s[l],d=a.getAttribute("data-ln-class").split(",");for(let h=0;h<d.length;h++){const u=d[h].trim().split(":");if(u.length!==2)continue;const i=u[0].trim(),c=u[1].trim();c in t&&a.classList.toggle(i,!!t[c])}}return e}function X(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)D(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function M(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const s=n.currentNode;s.textContent.indexOf("{{")!==-1&&(s.textContent=s.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,a){return t[a]!==void 0?t[a]:""}))}const o=function(s,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let s=0;s<r.length;s++){const l=r[s],a=l.attributes;for(let d=0;d<a.length;d++){const h=a[d];h.value.indexOf("{{")!==-1&&l.setAttribute(h.name,h.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function z(e,t,n,o,r,s){const l={};for(let d=0;d<e.children.length;d++){const h=e.children[d],u=h.getAttribute("data-ln-render-key");u&&(l[u]=h)}const a=document.createDocumentFragment();for(let d=0;d<t.length;d++){const h=t[d],u=String(o(h));let i=l[u];if(i)r(i,h,d);else{const c=G(n,s);if(!c||(M(c,h),i=c.firstElementChild,!i))continue;i.setAttribute("data-ln-render-key",u),r(i,h,d)}a.appendChild(i)}e.textContent="",e.appendChild(a)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=M,window.lnCore.fill=D,window.lnCore.lnFill=X,window.lnCore.renderList=z);function v(e,t,n){const o=e.getAttribute(t);return o===null?n:o}function Y(e,t,n){const o=parseInt(e.getAttribute(t),10);return isNaN(o)?n:o}function Z(e,t,n=!1){const o=e.getAttribute(t);if(o===null)return!!n;const r=o.trim().toLowerCase();return!(r==="false"||r==="0")}function ee(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const S=new Map;function te(e,t){const n=(e?e.join("|"):"")+"::"+t;if(S.has(n))return S.get(n);const o=new Set(e||[]),r=function(s,l){const a=s.getAttribute(l);return a!==null&&o.has(a)?a:t};return S.set(n,r),r}function ne(e,t,n){const o=parseFloat(e.getAttribute(t));return isNaN(o)?n:o}function oe(e,t,n){const o=e.getAttribute(t);if(!o)return n;try{return JSON.parse(o)}catch{return n}}function F(e,t,n,o,r){if(!e||t===null)return!0;const s=o||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const a=d=>{r?console.warn(d,r):console.warn(d)};if(l==="boolean"){const d=t.trim().toLowerCase();return d!==""&&d!=="true"&&d!=="false"&&d!=="1"&&d!=="0"?(a(`[${s}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const d=e.values||[];return d.includes(t)?!0:(a(`[${s}] Invalid value "${t}" for attribute "${n}". Allowed: ${d.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return a(`[${s}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const d=parseInt(t,10);return e.min!==void 0&&d<e.min?(a(`[${s}] Value ${d} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&d>e.max?(a(`[${s}] Value ${d} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(a(`[${s}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(d){return a(`[${s}] Invalid JSON for attribute "${n}": ${d.message}. Fallback: ${e.fallback}.`),!1}return!0}function re(e,t,n){for(const o in n){const[r,s,l]=n[o];Object.defineProperty(e,o,{get:function(){return r(t,s,l)},enumerable:!0,configurable:!0})}return e}function ie(e){const t={};for(const n in e){const o=e[n];if(!o||!o.prop)continue;let r=o.read;if(!r&&o.type)switch(o.type){case"enum":r=te(o.values,o.fallback);break;case"integer":r=Y;break;case"float":r=ne;break;case"boolean":r=Z;break;case"list":r=ee;break;case"json":r=oe;break;case"string":default:r=v;break}r||(r=v),t[o.prop]=[r,n,o.fallback]}return t}function se(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function le(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function O(e,t,n,o){if(e.nodeType!==1)return;const s=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l=Array.from(e.querySelectorAll(s));e.matches&&e.matches(s)&&l.push(e);for(const a of l)if(!a[n]){window.lnCore._persistSink&&a.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(a,t);try{a[n]=new o(a)}catch(d){console.error("["+n+"] init failed",a,d)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function ce(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function de(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function B(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function ae(e){const t=B(),n=e.observed||[];for(let o=0;o<n.length;o++){const r=n[o];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const r=t.byDeclaredAttr.get(o);r.some(s=>s.componentTag===e.componentTag)||r.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=le(e);if(o===null)t.reactiveWildcard.push(e);else for(const r of o)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function W(e,t,n,o){for(let r=0;r<e.length;r++){const s=e[r];if(!t[s.attribute])continue;const l=s.effects&&s.effects[n];l?l(t,n,o):s.onAttrChange&&(!s.declared||s.declared.has(n))&&s.onAttrChange(t,n,o)}}function ue(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=B(),r=o.byAttr.get(n);if(I()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&k(t)){const s=o.byDeclaredAttr.get(n),l=t.getAttribute(n);for(let a=0;a<s.length;a++)F(s[a].spec,l,n,s[a].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||r)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const s=o.byReactive.get(n);s&&W(s,t,n,e.oldValue),o.reactiveWildcard.length&&W(o.reactiveWildcard,t,n,e.oldValue)}if(r)for(let s=0;s<r.length;s++){const l=r[s];if(l.handler){l.handler(t,n,e.oldValue);continue}l.onAttributeChange&&t[l.attribute]?l.onAttributeChange(t,n):(O(t,l.selector,l.attribute,l.ComponentFn),l.onInit&&l.onInit(t))}}function fe(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,C(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{ue(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function j(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function he(e){const t=j();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const r=o.query,s=e.target.nodeType===1?e.target.matches(r)?e.target:e.target.closest(r):e.target.parentElement?e.target.parentElement.closest(r):null;s&&o.onSubtreeChange(s,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const s=t[r];O(o,s.selector,s.attribute,s.ComponentFn),s.onInit&&s.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const s=t[r],l=s.query,a=Array.from(o.querySelectorAll(l));o.matches&&o.matches(l)&&a.push(o);for(let d=0;d<a.length;d++){const h=a[d];if(!document.contains(h)){const u=h[s.attribute];if(u&&typeof u.destroy=="function")try{u.destroy()}catch(i){console.error("["+s.attribute+"] destroy failed",h,i)}delete h[s.attribute]}}}}}}function we(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,C(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{he(o)}catch(r){console.error("[ln-core] lifecycle handler failed",o.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function pe(e,t,n,o,r={}){const s=r.extraAttributes||[],l=r.onAttributeChange||null,a=r.onSubtreeChange||null,d=r.onInit||null,h=r.onAttrChange||null,u=r.effects||null,i=r.attributes||null,c=i?se(i):u,f=i?new Set(Object.keys(i)):null,p=r.persist||null;function w(x){const m=x||document.body;if(O(m,e,t,n),i&&I())for(const _ in i){const ve=i[_],R=Array.from(m.querySelectorAll("["+_+"]"));m.matches&&m.matches("["+_+"]")&&R.push(m);for(let T=0;T<R.length;T++){const L=R[T];k(L)&&F(ve,L.getAttribute(_),_,o,L)}}d&&d(m)}const g=[];if(e.indexOf("[")!==-1){const x=/\[([\w-]+)/g;let m;for(;(m=x.exec(e))!==null;)g.push(m[1])}else g.push(e);ae({selector:e,attribute:t,componentTag:o,attributes:i,ComponentFn:n,onInit:d,observed:g.concat(s),onAttributeChange:l,onAttrChange:h,effects:c,declared:f,persist:p}),fe();const y=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";j().push({selector:e,attribute:t,ComponentFn:n,onInit:d,onSubtreeChange:a,query:y}),we(),window[t]=w;function V(){ce()>0?de(function(){w(document.body)}):w(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",V):V(),w}function K(e){return(e||"").replace(/^#/,"")}function q(e){const t=e===void 0?location.hash:e,n={},o=K(t);if(!o)return n;const r=o.split("&");for(let s=0;s<r.length;s++){const l=r[s];if(!l)continue;const a=l.indexOf(":"),d=a>-1?l.slice(0,a):l,h=a>-1?l.slice(a+1):"";if(d)try{n[d]=decodeURIComponent(h)}catch{n[d]=h}}return n}function be(e){if(!e)return null;const t=q();return e in t?t[e]:null}function ge(e,t){if(!e)return;const n=q();t==null?delete n[e]:n[e]=String(t);const r=Object.keys(n).map(function(s){const l=n[s];return l===""?s:s+":"+encodeURIComponent(l)}).join("&");K(location.hash)!==r&&(location.hash=r)}function me(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function ye(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function _e(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ce(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ke(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Ae(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),r=o?o.split(",").map(function(s){try{return decodeURIComponent(s)}catch{return s}}).filter(Boolean):[];return{key:n,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=q,window.lnCore.hashGet=be,window.lnCore.hashSet=ge,window.lnCore.hashLinkClick=me,window.lnCore.resolveHashNamespace=ye,window.lnCore.hashSortEncode=_e,window.lnCore.hashSortDecode=Ce,window.lnCore.hashFilterEncode=ke,window.lnCore.hashFilterDecode=Ae),(function(){const e="data-ln-websocket-connector",t="lnWebsocketConnector";if(window[t]!==void 0)return;const n=1e3,o=3e4;function r(i){const c=i[t];c&&(c.command==="connect"?c._open():c._disconnect())}function s(i){const c=i[t];!c||c.command!=="connect"||(c._drop("url-changed"),c._open())}const l={"data-ln-websocket-connector":{prop:"command",type:"enum",values:["connect","disconnect"],fallback:"connect",effect:r,description:"Connection command set from outside: connect or disconnect"},"data-ln-websocket-connector-url":{prop:"url",read:v,type:"string",fallback:"",effect:s,description:"WebSocket endpoint URL (ws:// or wss://)"}},a=ie(l),d={"ln-websocket-connector:request-sync":"sync","ln-websocket-connector:request-query":"query","ln-websocket-connector:request-create":"create","ln-websocket-connector:request-update":"update","ln-websocket-connector:request-delete":"delete","ln-websocket-connector:request-bulk-delete":"bulk-delete"};function h(i,c){return i==="sync"?{since:c.since}:i==="query"?{query:c.query||{}}:i==="create"?{data:c.data,idempotencyKey:c.idempotencyKey}:i==="update"?{id:c.id,data:c.data,expected_version:c.expected_version,idempotencyKey:c.idempotencyKey}:i==="delete"?{id:c.id,idempotencyKey:c.idempotencyKey}:{ids:c.ids,idempotencyKey:c.idempotencyKey}}function u(i){this.dom=i,re(this,i,a),i[t]=this,this._socket=null,this._status="disconnected",this._attempt=0,this._timer=null,this._seq=0,this._pending=new Map,this._held=[];const c=this;this._onRequest=function(f){c._request(d[f.type],f.detail||{})};for(const f in d)i.addEventListener(f,this._onRequest);return this.command==="connect"&&this._open(),this}u.prototype._open=function(){if(this._socket||this._timer)return;const i=this,c=this.url;this._attempt++,this._status="connecting",b(this.dom,"ln-websocket-connector:connecting",{url:c,attempt:this._attempt});let f;try{f=new WebSocket(c)}catch(p){this._status="disconnected",this._attempt=0,this._failAll(this._held,p.message),this._held=[],b(this.dom,"ln-websocket-connector:disconnected",{url:c,code:0,reason:p.message,willReconnect:!1});return}this._socket=f,f.onopen=function(){i._status="connected",i._attempt=0,b(i.dom,"ln-websocket-connector:connected",{url:c});const p=i._held;i._held=[];for(let w=0;w<p.length;w++)i._send(p[w])},f.onmessage=function(p){i._receive(p.data)},f.onclose=function(p){i._socket=null,i._status="disconnected",i._failPending("connection closed");const w=i.command==="connect";b(i.dom,"ln-websocket-connector:disconnected",{url:c,code:p.code,reason:p.reason,willReconnect:w}),w&&i._scheduleReconnect()}},u.prototype._scheduleReconnect=function(){const i=this,c=Math.min(n*Math.pow(2,Math.max(0,this._attempt-1)),o);this._timer=setTimeout(function(){i._timer=null,i._open()},c)},u.prototype._drop=function(i){const c=!!(this._socket||this._timer);clearTimeout(this._timer),this._timer=null,this._attempt=0,this._socket&&(this._socket.onopen=this._socket.onmessage=this._socket.onclose=null,this._socket.close(1e3,i),this._socket=null),c&&(this._status="disconnected",this._failPending("connection closed"),b(this.dom,"ln-websocket-connector:disconnected",{url:this.url,code:1e3,reason:i,willReconnect:!1}))},u.prototype._disconnect=function(){this._drop("disconnect"),this._failAll(this._held,"disconnected"),this._held=[]},u.prototype._request=function(i,c){const f={ref:String(++this._seq),type:i,detail:c};this._status==="connected"?this._send(f):this.command==="connect"?this._held.push(f):this._fail(f,0,"disconnected",null)},u.prototype._send=function(i){this._pending.set(i.ref,i),this._socket.send(JSON.stringify(Object.assign({ref:i.ref,type:i.type},h(i.type,i.detail))))},u.prototype._receive=function(i){let c;try{c=JSON.parse(i)}catch{console.warn("[ln-websocket-connector] Ignored a frame that is not JSON:",i);return}if(c.ref!==void 0){const f=this._pending.get(String(c.ref));if(!f)return;this._pending.delete(f.ref),c.ok?this._resolve(f,c.content,c.message||null):this._fail(f,c.status||0,c.error,c.data);return}c.type==="changes"&&b(this.dom,"ln-websocket-connector:fetched",{data:{data:c.data||[],deleted:c.deleted||[],synced_at:c.synced_at},since:null,meta:null})},u.prototype._resolve=function(i,c,f){const p=i.detail,w=p.meta||null,g=this.dom;if(i.type==="sync")b(g,"ln-websocket-connector:fetched",{data:c,since:p.since,meta:w});else if(i.type==="query"){const E=p.query||{},y=c||{};b(g,"ln-websocket-connector:fetched",{data:y.data||[],total:y.total,filtered:y.filtered,offset:E.offset,queryGen:E.queryGen,meta:w})}else i.type==="create"?b(g,"ln-websocket-connector:created",{record:c,tempId:p.tempId,message:f,meta:w}):i.type==="update"?b(g,"ln-websocket-connector:updated",{record:c,id:p.id,message:f,meta:w}):i.type==="delete"?b(g,"ln-websocket-connector:deleted",{response:c,id:p.id,message:f,meta:w}):b(g,"ln-websocket-connector:bulk-deleted",{response:c,ids:p.ids,message:f,meta:w})},u.prototype._fail=function(i,c,f,p){const w=i.detail;b(this.dom,"ln-websocket-connector:error",{action:i.type,error:f,status:c,data:p||null,conflictData:c===409&&p||null,since:w.since,id:w.id,ids:w.ids,tempId:w.tempId,meta:w.meta||null})},u.prototype._failAll=function(i,c){for(let f=0;f<i.length;f++)this._fail(i[f],0,c,null)},u.prototype._failPending=function(i){const c=Array.from(this._pending.values());this._pending.clear(),this._failAll(c,i)},u.prototype.destroy=function(){if(this.dom[t]){for(const i in d)this.dom.removeEventListener(i,this._onRequest);clearTimeout(this._timer),this._timer=null,this._socket&&(this._socket.onopen=this._socket.onmessage=this._socket.onclose=null,this._socket.close(1e3,"destroy"),this._socket=null),this._pending.clear(),this._held=[],delete this.dom[t]}},pe(e,t,u,"ln-websocket-connector",{attributes:l})})()})();
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
|
|
3
|
+
"component": "ln-websocket-connector",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {
|
|
6
|
+
"data-ln-websocket-connector": {
|
|
7
|
+
"direction": null,
|
|
8
|
+
"sources": [
|
|
9
|
+
"src/ln-websocket-connector.js"
|
|
10
|
+
],
|
|
11
|
+
"type": "enum",
|
|
12
|
+
"values": [
|
|
13
|
+
"connect",
|
|
14
|
+
"disconnect"
|
|
15
|
+
],
|
|
16
|
+
"fallback": "connect",
|
|
17
|
+
"description": "Connection command set from outside: connect or disconnect"
|
|
18
|
+
},
|
|
19
|
+
"data-ln-websocket-connector-url": {
|
|
20
|
+
"direction": null,
|
|
21
|
+
"sources": [
|
|
22
|
+
"src/ln-websocket-connector.js"
|
|
23
|
+
],
|
|
24
|
+
"type": "string",
|
|
25
|
+
"fallback": "",
|
|
26
|
+
"description": "WebSocket endpoint URL (ws:// or wss://)"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|