@livenetworks/ashlar 1.6.1 → 2.0.1
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 +190 -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
|
@@ -0,0 +1,45 @@
|
|
|
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-form",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {
|
|
6
|
+
"data-ln-debug": {
|
|
7
|
+
"direction": null,
|
|
8
|
+
"sources": [
|
|
9
|
+
"ln-form-dev.scss"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"data-ln-form": {
|
|
13
|
+
"direction": null,
|
|
14
|
+
"sources": [
|
|
15
|
+
"ln-form-dev.scss",
|
|
16
|
+
"src/ln-form.js"
|
|
17
|
+
],
|
|
18
|
+
"type": "marker",
|
|
19
|
+
"description": "Identifies the form element as an enhanced ln-form"
|
|
20
|
+
},
|
|
21
|
+
"data-ln-form-action-edit": {
|
|
22
|
+
"direction": "author",
|
|
23
|
+
"sources": [
|
|
24
|
+
"src/ln-form.js"
|
|
25
|
+
],
|
|
26
|
+
"type": "string",
|
|
27
|
+
"fallback": "",
|
|
28
|
+
"description": "URL template or endpoint used when editing an existing record"
|
|
29
|
+
},
|
|
30
|
+
"data-ln-form-action-method": {
|
|
31
|
+
"direction": null,
|
|
32
|
+
"sources": [
|
|
33
|
+
"src/ln-form.js"
|
|
34
|
+
],
|
|
35
|
+
"type": "enum",
|
|
36
|
+
"values": [
|
|
37
|
+
"PUT",
|
|
38
|
+
"POST",
|
|
39
|
+
"PATCH"
|
|
40
|
+
],
|
|
41
|
+
"fallback": "PUT",
|
|
42
|
+
"description": "HTTP method used when submitting edit action"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,99 +1,107 @@
|
|
|
1
|
-
import { populateForm,
|
|
2
|
-
|
|
3
|
-
(function () {
|
|
4
|
-
const DOM_SELECTOR = 'data-ln-form';
|
|
5
|
-
const DOM_ATTRIBUTE = 'lnForm';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
import { populateForm, registerComponent, defineAttrs, attrSpec, attrStr } from '../../ln-core';
|
|
2
|
+
|
|
3
|
+
(function () {
|
|
4
|
+
const DOM_SELECTOR = 'data-ln-form';
|
|
5
|
+
const DOM_ATTRIBUTE = 'lnForm';
|
|
6
|
+
|
|
7
|
+
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
8
|
+
|
|
9
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
10
|
+
const ATTRIBUTES = {
|
|
11
|
+
'data-ln-form': { type: 'marker', description: 'Identifies the form element as an enhanced ln-form' },
|
|
12
|
+
'data-ln-form-action-edit': { prop: '_actionEdit', type: 'string', read: attrStr, fallback: '', description: 'URL template or endpoint used when editing an existing record' },
|
|
13
|
+
'data-ln-form-action-method': { prop: '_actionMethod', type: 'enum', values: ['PUT', 'POST', 'PATCH'], fallback: 'PUT', description: 'HTTP method used when submitting edit action' }
|
|
14
|
+
};
|
|
15
|
+
const ATTR_SPEC = attrSpec(ATTRIBUTES);
|
|
16
|
+
|
|
17
|
+
// ─── Component ─────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
function _component(form) {
|
|
20
|
+
this.dom = form;
|
|
21
|
+
defineAttrs(this, form, ATTR_SPEC);
|
|
22
|
+
this._baseAction = form.getAttribute('action') || '';
|
|
23
|
+
|
|
24
|
+
const self = this;
|
|
25
|
+
|
|
26
|
+
this._onLnFill = function (e) {
|
|
27
|
+
// Guard: only handle direct dispatches at this form, not bubbled
|
|
28
|
+
// events from [data-ln-fillable] children inside the form.
|
|
29
|
+
if (e.target !== self.dom) return;
|
|
30
|
+
if (e.detail) {
|
|
31
|
+
self.fill(e.detail);
|
|
32
|
+
self._applyActionMode(e.detail);
|
|
33
|
+
} else {
|
|
34
|
+
// Null record = "new" mode. Native reset fires the 'reset'
|
|
35
|
+
// event, which restores the base action below.
|
|
36
|
+
self.dom.reset();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
this._onReset = function () {
|
|
41
|
+
self._applyActionMode(null);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
form.addEventListener('ln-fill', this._onLnFill);
|
|
45
|
+
form.addEventListener('reset', this._onReset);
|
|
46
|
+
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_component.prototype.fill = function (data) {
|
|
51
|
+
const filled = populateForm(this.dom, data);
|
|
52
|
+
|
|
53
|
+
// Trigger events so reactive consumers (ln-validate, ln-autoresize)
|
|
54
|
+
// pick up the changes. SELECT/checkbox/radio -> 'change',
|
|
55
|
+
// everything else -> 'input'.
|
|
56
|
+
for (let k = 0; k < filled.length; k++) {
|
|
57
|
+
const el = filled[k];
|
|
58
|
+
const isChangeBased = el.tagName === 'SELECT' || el.type === 'checkbox' || el.type === 'radio';
|
|
59
|
+
el.dispatchEvent(new Event(isChangeBased ? 'change' : 'input', { bubbles: true }));
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
_component.prototype._ensureMethodInput = function () {
|
|
64
|
+
let input = this.dom.querySelector('input[name="_method"]');
|
|
65
|
+
if (!input) {
|
|
66
|
+
input = document.createElement('input');
|
|
67
|
+
input.type = 'hidden';
|
|
68
|
+
input.name = '_method';
|
|
69
|
+
input.value = '';
|
|
70
|
+
this.dom.appendChild(input);
|
|
71
|
+
}
|
|
72
|
+
return input;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
_component.prototype._applyActionMode = function (record) {
|
|
76
|
+
if (!this.dom.hasAttribute('data-ln-form-action-edit')) return;
|
|
77
|
+
|
|
78
|
+
const id = record && record.id != null && record.id !== '' ? record.id : null;
|
|
79
|
+
const methodInput = this._ensureMethodInput();
|
|
80
|
+
|
|
81
|
+
if (id !== null) {
|
|
82
|
+
const template = this._actionEdit;
|
|
83
|
+
if (template) {
|
|
84
|
+
this.dom.setAttribute('action', template.replace(':id', encodeURIComponent(id)));
|
|
85
|
+
} else {
|
|
86
|
+
this.dom.setAttribute('action', this._baseAction.replace(/\/$/, '') + '/' + encodeURIComponent(id));
|
|
87
|
+
}
|
|
88
|
+
methodInput.value = this._actionMethod || 'PUT';
|
|
89
|
+
} else {
|
|
90
|
+
this.dom.setAttribute('action', this._baseAction);
|
|
91
|
+
methodInput.value = '';
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
_component.prototype.destroy = function () {
|
|
96
|
+
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
97
|
+
this.dom.removeEventListener('ln-fill', this._onLnFill);
|
|
98
|
+
this.dom.removeEventListener('reset', this._onReset);
|
|
99
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ─── Init ──────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-form', {
|
|
105
|
+
attributes: ATTRIBUTES
|
|
106
|
+
});
|
|
107
|
+
})();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# ln-http
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
> A window-level HTTP concurrency coordinator (`window.lnHttp`). It transparently intercepts `fetch()` to call
|
|
4
|
+
> `AbortController.abort()` on superseded in-flight GET/HEAD requests targeting the exact same URL. Additionally, it listens
|
|
5
|
+
> globally for `ln-http:request` CustomEvents bearing a unique `key`: automatically aborting any running request with the same
|
|
6
|
+
> key, executing the fetch, and dispatching `ln-http:response` or `ln-http:error`.
|
|
6
7
|
|
|
7
8
|
---
|
|
8
9
|
|
|
@@ -68,9 +69,13 @@ element.dispatchEvent(new CustomEvent('ln-http:request', {
|
|
|
68
69
|
|
|
69
70
|
---
|
|
70
71
|
|
|
71
|
-
## ⚡ DOM Events (Path B response lifecycle)
|
|
72
|
+
## ⚡ DOM Events (Path B response lifecycle & declarative control)
|
|
73
|
+
|
|
74
|
+
### `ln-http:cancel`
|
|
75
|
+
Listened on `document`. Declaratively cancels in-flight requests without calling imperative window methods.
|
|
76
|
+
- `detail`: `{ key?: string, url?: string, all?: boolean }`
|
|
72
77
|
|
|
73
|
-
Both events bubble from the element that dispatched the original `'ln-http:request'`.
|
|
78
|
+
Both response events bubble from the element that dispatched the original `'ln-http:request'`.
|
|
74
79
|
|
|
75
80
|
### `ln-http:response`
|
|
76
81
|
Fired when `fetch` resolves. The consumer must branch on `ok`/`status` and parse the raw body.
|
|
@@ -92,7 +97,7 @@ Fired when network-level failures reject the fetch promise (excluding aborts).
|
|
|
92
97
|
|
|
93
98
|
## 🔧 Internals
|
|
94
99
|
|
|
95
|
-
Source: `
|
|
100
|
+
Source: `components/ln-http/ln-http.js`. A **service-style global**: wraps `window.fetch`, listens on `document`, no DOM instance, no `data-ln-*`, no MutationObserver. Two closure-private `Map`s hold all state — `_inflight` (`"METHOD URL" → AbortController`, Path A) and `_keyed` (`consumer key → AbortController`, Path B) — plus `_origFetch`, the unwrapped `fetch` captured at load, used to restore on `destroy()`.
|
|
96
101
|
|
|
97
102
|
### Parasitic design
|
|
98
103
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";function S(t){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return t?window.lnCore._debugIsContained(t):window.lnCore._debugSink!==null;if(t&&t.closest){const e=t.closest("[data-ln-debug]");return!(!e||typeof document<"u"&&e===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 t=console.warn;console.warn=function(...e){if(typeof e[0]=="string"&&(e[0].startsWith("[ln-")||e[0].startsWith("[lnCore"))){let d=null;for(let a=1;a<e.length;a++)if(e[a]&&e[a].nodeType===1){d=e[a];break}if(!S(d))return}t.apply(console,e)}}function p(t,e,o){const d=o||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",e,t,d),t.dispatchEvent(new CustomEvent(e,{bubbles:!0,detail:d}))}function C(t,e){if(!document.body){document.addEventListener("DOMContentLoaded",function(){C(t,e)}),console.warn("["+e+'] Script loaded before <body> — add "defer" to your <script> tag');return}t()}const m={};function k(t,e){m[t]=e}function v(t){return m[t]||{ingress:e=>e,egress:e=>e}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=k,window.lnCore.getDataMapper=v);function L(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,C(function(){new MutationObserver(function(){p(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const y={};function x(t,e){if(!t||typeof e!="object")return;const o=t.toLowerCase().split("-")[0];y[o]=e}function H(t){if(!t)return null;const e=t.toLowerCase().split("-")[0];return y[e]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=x,window.lnCore.getLocaleFallback=H,window.lnCore.ensureLocaleObserver=L);const b={};function O(t,e){b[t]||(b[t]=document.querySelector('[data-ln-template="'+t+'"]'));const o=b[t];return o?o.content.cloneNode(!0):(console.warn("["+(e||"ln-core")+'] Template "'+t+'" not found'),null)}function E(t,e){if(!t||!e)return t;const o=t.querySelectorAll("[data-ln-field]");for(let n=0;n<o.length;n++){const r=o[n],l=r.getAttribute("data-ln-field");e[l]!=null&&(r.textContent=e[l])}const d=t.querySelectorAll("[data-ln-attr]");for(let n=0;n<d.length;n++){const r=d[n],l=r.getAttribute("data-ln-attr").split(",");for(let i=0;i<l.length;i++){const c=l[i].trim().split(":");if(c.length!==2)continue;const u=c[0].trim(),f=c[1].trim();e[f]!=null&&r.setAttribute(u,e[f])}}const a=t.querySelectorAll("[data-ln-show]");for(let n=0;n<a.length;n++){const r=a[n],l=r.getAttribute("data-ln-show");l in e&&r.classList.toggle("hidden",!e[l])}const s=t.querySelectorAll("[data-ln-class]");for(let n=0;n<s.length;n++){const r=s[n],l=r.getAttribute("data-ln-class").split(",");for(let i=0;i<l.length;i++){const c=l[i].trim().split(":");if(c.length!==2)continue;const u=c[0].trim(),f=c[1].trim();f in e&&r.classList.toggle(u,!!e[f])}}return t}function D(t,e){t.matches&&t.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",t,e??null),t.dispatchEvent(new CustomEvent("ln-fill",{detail:e??null,bubbles:!0})));const o=t.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let d=0;d<o.length;d++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",o[d],e??null),o[d].dispatchEvent(new CustomEvent("ln-fill",{detail:e??null,bubbles:!0}));return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(t){if(!(!t.target.matches||!t.target.matches("[data-ln-fillable]")))if(t.detail)E(t.target,t.detail);else{const e=t.target.querySelectorAll("[data-ln-field]");for(let o=0;o<e.length;o++)e[o].textContent=""}})));function _(t,e){if(!t||!e)return t;const o=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(;o.nextNode();){const s=o.currentNode;s.textContent.indexOf("{{")!==-1&&(s.textContent=s.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(n,r){return e[r]!==void 0?e[r]:""}))}const d=function(s,n){return e[n]!==void 0?e[n]:""},a=Array.from(t.querySelectorAll("*"));t.nodeType===1&&a.push(t);for(let s=0;s<a.length;s++){const n=a[s],r=n.attributes;for(let l=0;l<r.length;l++){const i=r[l];i.value.indexOf("{{")!==-1&&n.setAttribute(i.name,i.value.replace(/\{\{\s*(\w+)\s*\}\}/g,d))}}return t}function F(t,e,o,d,a,s){const n={};for(let l=0;l<t.children.length;l++){const i=t.children[l],c=i.getAttribute("data-ln-render-key");c&&(n[c]=i)}const r=document.createDocumentFragment();for(let l=0;l<e.length;l++){const i=e[l],c=String(d(i));let u=n[c];if(u)a(u,i,l);else{const f=O(o,s);if(!f||(_(f,i),u=f.firstElementChild,!u))continue;u.setAttribute("data-ln-render-key",c),a(u,i,l)}r.appendChild(u)}t.textContent="",t.appendChild(r)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=_,window.lnCore.fill=E,window.lnCore.lnFill=D,window.lnCore.renderList=F),typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function A(t){return(t||"").replace(/^#/,"")}function g(t){const e=t===void 0?location.hash:t,o={},d=A(e);if(!d)return o;const a=d.split("&");for(let s=0;s<a.length;s++){const n=a[s];if(!n)continue;const r=n.indexOf(":"),l=r>-1?n.slice(0,r):n,i=r>-1?n.slice(r+1):"";if(l)try{o[l]=decodeURIComponent(i)}catch{o[l]=i}}return o}function T(t){if(!t)return null;const e=g();return t in e?e[t]:null}function M(t,e){if(!t)return;const o=g();e==null?delete o[t]:o[t]=String(e);const a=Object.keys(o).map(function(s){const n=o[s];return n===""?s:s+":"+encodeURIComponent(n)}).join("&");A(location.hash)!==a&&(location.hash=a)}function q(t){return t.button===1||t.ctrlKey||t.metaKey||t.shiftKey?!1:(t.preventDefault(),!0)}function B(t,e){if(!t||!t.hasAttribute("data-ln-hash"))return null;const o=t.getAttribute("data-ln-hash");if(o&&o.trim()!=="")return o.trim();const d=t.getAttribute("data-ln-sort")||t.getAttribute("data-ln-search-for")||t.getAttribute("data-ln-search")||t.getAttribute("data-ln-filter")||t.id;return d?e?d+"-"+e:d:e||null}function j(t,e){return!e||e==="none"||t===null||t===void 0?null:String(t)+"."+e}function W(t){return!t||typeof t!="string"?null:t.endsWith(".asc")?{fieldOrColumn:t.slice(0,-4),direction:"asc"}:t.endsWith(".desc")?{fieldOrColumn:t.slice(0,-5),direction:"desc"}:null}function U(t,e){return!t||!Array.isArray(e)||e.length===0?null:t+":"+e.map(encodeURIComponent).join(",")}function I(t){if(!t||typeof t!="string")return null;const e=t.indexOf(":");if(e===-1)return null;const o=t.slice(0,e),d=t.slice(e+1),a=d?d.split(",").map(function(s){try{return decodeURIComponent(s)}catch{return s}}).filter(Boolean):[];return{key:o,values:a}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=g,window.lnCore.hashGet=T,window.lnCore.hashSet=M,window.lnCore.hashLinkClick=q,window.lnCore.resolveHashNamespace=B,window.lnCore.hashSortEncode=j,window.lnCore.hashSortDecode=W,window.lnCore.hashFilterEncode=U,window.lnCore.hashFilterDecode=I);function G(t){if(typeof t=="string")return t;if(t&&typeof t=="object"){if(typeof t.href=="string")return t.href;if(typeof t.url=="string")return t.url}return String(t||"")}function K(t,e){return e&&e.method?String(e.method).toUpperCase():t&&typeof t=="object"&&t.method?String(t.method).toUpperCase():"GET"}function N(t,e){return(e||"GET")+" "+(t||"")}function R(t){const e=(t||"").toUpperCase();return e==="GET"||e==="HEAD"}(function(){if(window.lnHttp)return;const t=window.fetch.bind(window),e=new Map,o=new Map;function d(n,r){r=r||{};const l=G(n),i=K(n,r),c=N(l,i);R(i)&&e.has(c)&&(e.get(c).abort(),e.delete(c));const u=new AbortController,f=r.signal;let h=null;f&&(f.aborted?u.abort(f.reason):(h=function(){u.abort(f.reason)},f.addEventListener("abort",h,{once:!0})));const w=Object.assign({},r,{signal:u.signal});return e.set(c,u),t(n,w).finally(function(){f&&h&&f.removeEventListener("abort",h),e.get(c)===u&&e.delete(c)})}d.toString=function(){return"function fetch() { [ln-http wrapped] }"},window.fetch=d;function a(n){if(!n.detail||!n.detail.url)return;const r=n.target,l=(n.detail.method||(n.detail.body?"POST":"GET")).toUpperCase(),i=n.detail.key;i&&o.has(i)&&(o.get(i).abort(),o.delete(i));const c=new AbortController,u=n.detail.signal;let f=null;u&&(u.aborted?c.abort(u.reason):(f=function(){c.abort(u.reason)},u.addEventListener("abort",f,{once:!0}))),i&&o.set(i,c);const h={method:l,signal:c.signal};n.detail.body!==void 0&&(h.body=n.detail.body),window.fetch(n.detail.url,h).then(function(w){u&&f&&u.removeEventListener("abort",f),i&&o.get(i)===c&&o.delete(i),p(r,"ln-http:response",{ok:w.ok,status:w.status,response:w})}).catch(function(w){u&&f&&u.removeEventListener("abort",f),i&&o.get(i)===c&&o.delete(i),!(w&&w.name==="AbortError")&&p(r,"ln-http:error",{ok:!1,status:0,error:w})})}function s(n){const r=n.detail||{};r.all?window.lnHttp.cancelAll():r.key?window.lnHttp.cancelByKey(r.key):r.url&&window.lnHttp.cancel(r.url)}document.addEventListener("ln-http:request",a),document.addEventListener("ln-http:cancel",s),window.lnHttp={cancel:function(n){let r=!1;return e.forEach(function(l,i){i.endsWith(" "+n)&&(l.abort(),e.delete(i),r=!0)}),r},cancelByKey:function(n){return o.has(n)?(o.get(n).abort(),o.delete(n),!0):!1},cancelAll:function(){e.forEach(function(n){n.abort()}),e.clear(),o.forEach(function(n){n.abort()}),o.clear()},get inflight(){const n=[];return e.forEach(function(r,l){const i=l.indexOf(" ");n.push({method:l.slice(0,i),url:l.slice(i+1)})}),o.forEach(function(r,l){n.push({key:l})}),n},destroy:function(){window.lnHttp.cancelAll(),document.removeEventListener("ln-http:request",a),document.removeEventListener("ln-http:cancel",s),window.fetch=t,delete window.lnHttp}}})()})();
|
|
@@ -0,0 +1,6 @@
|
|
|
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-http",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {}
|
|
6
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════
|
|
2
|
+
// http-core.js — Pure helpers for ln-http transport supervisor
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Accept string | URL | Request | any → return string URL.
|
|
7
|
+
* @param {string|URL|Request|*} resource
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export function extractUrl(resource) {
|
|
11
|
+
if (typeof resource === 'string') return resource;
|
|
12
|
+
if (resource && typeof resource === 'object') {
|
|
13
|
+
if (typeof resource.href === 'string') return resource.href;
|
|
14
|
+
if (typeof resource.url === 'string') return resource.url;
|
|
15
|
+
}
|
|
16
|
+
return String(resource || '');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Extract HTTP method from options or Request, default 'GET', uppercased.
|
|
21
|
+
* @param {*} resource
|
|
22
|
+
* @param {Object} [options]
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
export function extractMethod(resource, options) {
|
|
26
|
+
if (options && options.method) return String(options.method).toUpperCase();
|
|
27
|
+
if (resource && typeof resource === 'object' && resource.method) {
|
|
28
|
+
return String(resource.method).toUpperCase();
|
|
29
|
+
}
|
|
30
|
+
return 'GET';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build deduplication cache key: "METHOD URL".
|
|
35
|
+
* @param {string} url
|
|
36
|
+
* @param {string} method
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
export function buildHttpKey(url, method) {
|
|
40
|
+
return (method || 'GET') + ' ' + (url || '');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if the HTTP method is eligible for transparent deduplication (GET, HEAD).
|
|
45
|
+
* @param {string} method
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
export function isIdempotentMethod(method) {
|
|
49
|
+
const m = (method || '').toUpperCase();
|
|
50
|
+
return m === 'GET' || m === 'HEAD';
|
|
51
|
+
}
|
|
@@ -39,17 +39,19 @@
|
|
|
39
39
|
// and _keyed (Path B, key-keyed). Aborts from either side are
|
|
40
40
|
// idempotent and cooperate cleanly.
|
|
41
41
|
//
|
|
42
|
-
// Public API
|
|
43
|
-
//
|
|
44
|
-
// .
|
|
45
|
-
// .
|
|
46
|
-
// .
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
42
|
+
// Public API & Event Control:
|
|
43
|
+
// ln-http:cancel — event on document { key?, url?, all? } to abort in-flight requests.
|
|
44
|
+
// window.lnHttp.cancel(url) — abort any Path A in-flight whose URL matches.
|
|
45
|
+
// window.lnHttp.cancelByKey(key) — abort the Path B in-flight with this key.
|
|
46
|
+
// window.lnHttp.cancelAll() — abort every in-flight (both paths).
|
|
47
|
+
// window.lnHttp.inflight — getter; returns Array<{ url, method, key? }>
|
|
48
|
+
// covering both paths, for debugging.
|
|
49
|
+
// window.lnHttp.destroy() — restore original fetch, remove document
|
|
50
|
+
// listeners, clear all in-flight queues.
|
|
51
|
+
// Used in dev hot-reload and tests.
|
|
51
52
|
|
|
52
53
|
import { dispatch } from '../../ln-core';
|
|
54
|
+
import { extractUrl, extractMethod, buildHttpKey, isIdempotentMethod } from './http-core';
|
|
53
55
|
|
|
54
56
|
(function () {
|
|
55
57
|
if (window.lnHttp) return; // double-load guard
|
|
@@ -58,37 +60,17 @@ import { dispatch } from '../../ln-core';
|
|
|
58
60
|
const _inflight = new Map(); // "METHOD URL" → AbortController (Path A)
|
|
59
61
|
const _keyed = new Map(); // consumer key → AbortController (Path B)
|
|
60
62
|
|
|
61
|
-
// ─── helpers ───────────────────────────────────────────────────
|
|
62
|
-
|
|
63
|
-
// Accept string | URL | Request → return absolute URL string.
|
|
64
|
-
function _extractUrl(resource) {
|
|
65
|
-
if (typeof resource === 'string') return resource;
|
|
66
|
-
if (resource instanceof URL) return resource.href;
|
|
67
|
-
if (resource instanceof Request) return resource.url;
|
|
68
|
-
return String(resource); // last-resort coercion
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Extract method from options OR Request, default GET, uppercased.
|
|
72
|
-
function _extractMethod(resource, options) {
|
|
73
|
-
if (options && options.method) return String(options.method).toUpperCase();
|
|
74
|
-
if (resource instanceof Request) return resource.method.toUpperCase();
|
|
75
|
-
return 'GET';
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function _key(url, method) { return method + ' ' + url; }
|
|
79
|
-
function _isIdempotent(method) { return method === 'GET' || method === 'HEAD'; }
|
|
80
|
-
|
|
81
63
|
// ─── Path A: window.fetch wrapper ─────────────────────────────
|
|
82
64
|
|
|
83
65
|
function _wrappedFetch(resource, options) {
|
|
84
66
|
options = options || {};
|
|
85
67
|
|
|
86
|
-
const url =
|
|
87
|
-
const method =
|
|
88
|
-
const key =
|
|
68
|
+
const url = extractUrl(resource);
|
|
69
|
+
const method = extractMethod(resource, options);
|
|
70
|
+
const key = buildHttpKey(url, method);
|
|
89
71
|
|
|
90
72
|
// Idempotent dedup — abort previous in-flight on same key.
|
|
91
|
-
if (
|
|
73
|
+
if (isIdempotentMethod(method) && _inflight.has(key)) {
|
|
92
74
|
_inflight.get(key).abort();
|
|
93
75
|
_inflight.delete(key);
|
|
94
76
|
}
|
|
@@ -189,7 +171,19 @@ import { dispatch } from '../../ln-core';
|
|
|
189
171
|
});
|
|
190
172
|
}
|
|
191
173
|
|
|
174
|
+
function _onCancel(e) {
|
|
175
|
+
const detail = e.detail || {};
|
|
176
|
+
if (detail.all) {
|
|
177
|
+
window.lnHttp.cancelAll();
|
|
178
|
+
} else if (detail.key) {
|
|
179
|
+
window.lnHttp.cancelByKey(detail.key);
|
|
180
|
+
} else if (detail.url) {
|
|
181
|
+
window.lnHttp.cancel(detail.url);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
192
185
|
document.addEventListener('ln-http:request', _onRequest);
|
|
186
|
+
document.addEventListener('ln-http:cancel', _onCancel);
|
|
193
187
|
|
|
194
188
|
// ─── Public API ───────────────────────────────────────────────
|
|
195
189
|
|
|
@@ -231,6 +225,7 @@ import { dispatch } from '../../ln-core';
|
|
|
231
225
|
destroy: function () {
|
|
232
226
|
window.lnHttp.cancelAll();
|
|
233
227
|
document.removeEventListener('ln-http:request', _onRequest);
|
|
228
|
+
document.removeEventListener('ln-http:cancel', _onCancel);
|
|
234
229
|
window.fetch = _origFetch;
|
|
235
230
|
delete window.lnHttp;
|
|
236
231
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# ln-icon
|
|
2
2
|
|
|
3
|
+
> Applied to standard SVG references (`<svg class="ln-icon"><use href="#ln-icon-home"></use></svg>`). It monitors the DOM via `MutationObserver` for `<use>` tags, dynamically fetches missing SVG paths from a CDN or custom asset endpoint, caches them in `localStorage` under the `lni:` prefix, and injects them into a single hidden `#ln-icon-sprite` symbol sheet at the start of `<body>`. It executes zero JS rendering after hydration, leaving styling and color inheritance entirely to CSS `currentColor`.
|
|
4
|
+
|
|
3
5
|
A zero-dependency, local-first **On-Demand SVG Sprite Generator** that dynamically monitors, fetches, and compiles SVG icons at runtime.
|
|
4
6
|
|
|
5
7
|
Instead of bundling thousands of heavy vector paths or requiring complex manual build steps, it intercepts standard DOM `<use>` tags, fetches vector definitions from a remote CDN, caches them in `localStorage`, and injects them into a single unified hidden SVG sprite sheet.
|
|
@@ -8,10 +10,10 @@ Instead of bundling thousands of heavy vector paths or requiring complex manual
|
|
|
8
10
|
|
|
9
11
|
## 🧭 Philosophy & Architecture
|
|
10
12
|
|
|
11
|
-
1. **Declarative On-Demand Rendering:** Icons are declared directly in HTML. The component monitors the DOM via `MutationObserver` for `<use>` references with `#ln-` and `#
|
|
13
|
+
1. **Declarative On-Demand Rendering:** Icons are declared directly in HTML. The component monitors the DOM via `MutationObserver` for `<use>` references with `#ln-icon-` and `#ln-icon-custom-` prefixes. It only fetches and compiles icons that are actively present on the page.
|
|
12
14
|
2. **Dual-Prefix Routing:**
|
|
13
|
-
- **`#ln-{name}`**: Automatically routes to the [Tabler Icons](https://tabler.io/icons) library fetched from a public CDN. No configuration required.
|
|
14
|
-
- **`#
|
|
15
|
+
- **`#ln-icon-{name}`**: Automatically routes to the [Tabler Icons](https://tabler.io/icons) library fetched from a public CDN. No configuration required.
|
|
16
|
+
- **`#ln-icon-custom-{name}`**: Routes to a custom corporate CDN defined via global window settings.
|
|
15
17
|
3. **Local Caching Layer:** Fetched SVG path structures are instantly cached in `localStorage` under `lni:{id}`. Subsequent visits render icons instantly with zero network roundtrips.
|
|
16
18
|
|
|
17
19
|
---
|
|
@@ -62,7 +64,7 @@ Configure these properties before script initialization:
|
|
|
62
64
|
| Variable | Default | Description |
|
|
63
65
|
| :--- | :--- | :--- |
|
|
64
66
|
| `LN_ICON_CDN` | `https://cdn.jsdelivr.net/npm/@tabler/icons@3.31.0/icons/outline` | Base CDN URL for Tabler Icons. |
|
|
65
|
-
| `LN_ICON_CUSTOM_CDN` | `null` | Base CDN URL for custom `#
|
|
67
|
+
| `LN_ICON_CUSTOM_CDN` | `null` | Base CDN URL for custom `#ln-icon-custom-` prefixed SVG resources. |
|
|
66
68
|
|
|
67
69
|
---
|
|
68
70
|
|
|
@@ -84,14 +86,14 @@ useElement.setAttribute('href', '#ln-icon-check');
|
|
|
84
86
|
## ⚠️ Common Pitfalls
|
|
85
87
|
|
|
86
88
|
- **Forgetting `ln-icon` Class:** Standard SVGs default to `100%` width/height. Failing to include the `ln-icon` class will cause the icon to blow up to full viewport size.
|
|
87
|
-
- **Incorrect Prefix Configuration:** Forgetting to define `window.LN_ICON_CUSTOM_CDN` when using `#
|
|
89
|
+
- **Incorrect Prefix Configuration:** Forgetting to define `window.LN_ICON_CUSTOM_CDN` when using `#ln-icon-custom-` will cause the loader to fail silently with undefined endpoint errors.
|
|
88
90
|
- **Omitting `aria-hidden="true"`:** Screen readers attempt to read SVG nodes. Always decorate decorative icons with `aria-hidden="true"`, or include an `aria-label` on their parent button.
|
|
89
91
|
|
|
90
92
|
---
|
|
91
93
|
|
|
92
94
|
## 🔧 Internals
|
|
93
95
|
|
|
94
|
-
Source: `
|
|
96
|
+
Source: `components/ln-icon/ln-icon.js`. Routing is purely prefix-based — no config lists, no runtime mapping. Symbol IDs in the generated sprite mirror the full `href` value minus `#` (e.g. `#ln-icon-custom-file-pdf` → `<symbol id="ln-icon-custom-file-pdf">`).
|
|
95
97
|
|
|
96
98
|
### Scan
|
|
97
99
|
|
|
@@ -103,7 +105,7 @@ Two in-memory `Set`s (`loaded`, `pending`), keyed by full `href`, prevent duplic
|
|
|
103
105
|
|
|
104
106
|
### Fetch + symbol injection
|
|
105
107
|
|
|
106
|
-
On a cache miss: resolve the CDN URL (
|
|
108
|
+
On a cache miss: resolve the CDN URL (`#ln-icon-custom-` → `LN_ICON_CUSTOM_CDN`, `#ln-icon-` → `LN_ICON_CDN`; `#ln-icon-custom-` bails silently if the custom CDN isn't configured), `fetch()`, then parse the raw SVG string — extract `viewBox` (fallback `'0 0 24 24'`), the inner content between the `<svg>` tags, and root presentation attributes (`fill`, `stroke`, `stroke-width`, `stroke-linecap`, `stroke-linejoin`). A `<symbol>` is built from these and appended to the sprite's `<defs>`; the raw SVG is also written back to `localStorage`. Errors delete the `pending` entry silently — the icon stays blank, no retry.
|
|
107
109
|
|
|
108
110
|
### Sprite element
|
|
109
111
|
|
|
@@ -123,8 +125,13 @@ Tabler SVGs use `stroke="currentColor"`, so rendered icons inherit the nearest a
|
|
|
123
125
|
|
|
124
126
|
### Cross-component icon injection
|
|
125
127
|
|
|
126
|
-
Several components inject `<use>` elements dynamically rather than authoring them in HTML: `ln-toast` (`#ln-icon-x` dismiss button), `ln-upload` (`#
|
|
128
|
+
Several components inject `<use>` elements dynamically rather than authoring them in HTML: `ln-toast` (`#ln-icon-x` dismiss button), `ln-upload` (`#ln-icon-custom-file[-pdf|-doc|-epub]` per item, `#ln-icon-x` remove button), `ln-confirm` (swaps an existing `<use href>` to `#ln-icon-check` during confirm, restores on reset). All route through the same scan/fetch pipeline — no special-casing needed since detection is attribute-based, not author-time. `ln-sort` is the opposite case: its three trigger icons are statically authored in HTML (see `components/ln-sort/README.md`), never injected.
|
|
127
129
|
|
|
128
130
|
### Offline behavior
|
|
129
131
|
|
|
130
|
-
Uncached icons fail silently (`.catch()`) if the page loads offline — the icon stays blank. For offline-first deployments, self-host the SVG set and point `window.LN_ICON_CDN` at a local server before the library initializes; `vite.config.js` copies `
|
|
132
|
+
Uncached icons fail silently (`.catch()`) if the page loads offline — the icon stays blank. For offline-first deployments, self-host the SVG set and point `window.LN_ICON_CDN` at a local server before the library initializes; `vite.config.js` copies `components/ln-icon/icons/*.svg` → `dist/icons/` at build for this purpose.
|
|
133
|
+
|
|
134
|
+
### Security & Trust Boundary
|
|
135
|
+
|
|
136
|
+
`ln-icon` dynamically fetches SVG markup from CDNs and injects it via `innerHTML` into `<symbol>` definitions without client-side sanitization. For threat modeling, `localStorage` persistence implications, strict CSP directives (`connect-src`), and self-hosting / offline SVG sprite guidance, see the [Dynamic SVG Icon Trust Boundary](../../docs/architecture/security.md#7-dynamic-svg-icon-trust-boundary-ln-icons) documentation in `docs/architecture/security.md`.
|
|
137
|
+
|
|
@@ -0,0 +1,6 @@
|
|
|
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-icon",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {}
|
|
6
|
+
}
|