@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 @@
|
|
|
1
|
+
(function(){"use strict";function K(){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 A(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 r=null;for(let o=1;o<t.length;o++)if(t[o]&&t[o].nodeType===1){r=t[o];break}if(!A(r))return}e.apply(console,t)}}function q(e,t,n){const r=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,r),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:r}))}function z(e,t,n){const r=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,r);const o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:r});return e.dispatchEvent(o),o}function m(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){m(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const N={};function G(e,t){N[e]=t}function X(e){return N[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=G,window.lnCore.getDataMapper=X);function Y(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,m(function(){new MutationObserver(function(){q(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const $={};function Z(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];$[n]=t}function ee(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return $[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=Z,window.lnCore.getLocaleFallback=ee,window.lnCore.ensureLocaleObserver=Y);const v={};function te(e,t){v[e]||(v[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=v[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 a=0;a<n.length;a++){const c=n[a],i=c.getAttribute("data-ln-field");t[i]!=null&&(c.textContent=t[i])}const r=e.querySelectorAll("[data-ln-attr]");for(let a=0;a<r.length;a++){const c=r[a],i=c.getAttribute("data-ln-attr").split(",");for(let u=0;u<i.length;u++){const d=i[u].trim().split(":");if(d.length!==2)continue;const l=d[0].trim(),f=d[1].trim();t[f]!=null&&c.setAttribute(l,t[f])}}const o=e.querySelectorAll("[data-ln-show]");for(let a=0;a<o.length;a++){const c=o[a],i=c.getAttribute("data-ln-show");i in t&&c.classList.toggle("hidden",!t[i])}const s=e.querySelectorAll("[data-ln-class]");for(let a=0;a<s.length;a++){const c=s[a],i=c.getAttribute("data-ln-class").split(",");for(let u=0;u<i.length;u++){const d=i[u].trim().split(":");if(d.length!==2)continue;const l=d[0].trim(),f=d[1].trim();f in t&&c.classList.toggle(l,!!t[f])}}return e}function ne(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 r=0;r<n.length;r++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[r],t??null),n[r].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 R(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(a,c){return t[c]!==void 0?t[c]:""}))}const r=function(s,a){return t[a]!==void 0?t[a]:""},o=Array.from(e.querySelectorAll("*"));e.nodeType===1&&o.push(e);for(let s=0;s<o.length;s++){const a=o[s],c=a.attributes;for(let i=0;i<c.length;i++){const u=c[i];u.value.indexOf("{{")!==-1&&a.setAttribute(u.name,u.value.replace(/\{\{\s*(\w+)\s*\}\}/g,r))}}return e}function re(e,t,n,r,o,s){const a={};for(let i=0;i<e.children.length;i++){const u=e.children[i],d=u.getAttribute("data-ln-render-key");d&&(a[d]=u)}const c=document.createDocumentFragment();for(let i=0;i<t.length;i++){const u=t[i],d=String(r(u));let l=a[d];if(l)o(l,u,i);else{const f=te(n,s);if(!f||(R(f,u),l=f.firstElementChild,!l))continue;l.setAttribute("data-ln-render-key",d),o(l,u,i)}c.appendChild(l)}e.textContent="",e.appendChild(c)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=R,window.lnCore.fill=D,window.lnCore.lnFill=ne,window.lnCore.renderList=re);function I(e,t,n){const r=e.getAttribute(t);return r===null?n:r}function oe(e,t,n){const r=parseInt(e.getAttribute(t),10);return isNaN(r)?n:r}function F(e,t,n=!1){const r=e.getAttribute(t);if(r===null)return!!n;const o=r.trim().toLowerCase();return!(o==="false"||o==="0")}function ie(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const _=new Map;function se(e,t){const n=(e?e.join("|"):"")+"::"+t;if(_.has(n))return _.get(n);const r=new Set(e||[]),o=function(s,a){const c=s.getAttribute(a);return c!==null&&r.has(c)?c:t};return _.set(n,o),o}function ae(e,t,n){const r=parseFloat(e.getAttribute(t));return isNaN(r)?n:r}function le(e,t,n){const r=e.getAttribute(t);if(!r)return n;try{return JSON.parse(r)}catch{return n}}function M(e,t,n,r,o){if(!e||t===null)return!0;const s=r||"ln-component",a=e.type;if(a==="trigger"||a==="marker"||a==="string"||a==="list"||!a||t===""&&e.fallback!==void 0)return!0;const c=i=>{o?console.warn(i,o):console.warn(i)};if(a==="boolean"){const i=t.trim().toLowerCase();return i!==""&&i!=="true"&&i!=="false"&&i!=="1"&&i!=="0"?(c(`[${s}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(a==="enum"){const i=e.values||[];return i.includes(t)?!0:(c(`[${s}] Invalid value "${t}" for attribute "${n}". Allowed: ${i.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(a==="integer"){if(!/^-?\d+$/.test(t))return c(`[${s}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const i=parseInt(t,10);return e.min!==void 0&&i<e.min?(c(`[${s}] Value ${i} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&i>e.max?(c(`[${s}] Value ${i} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(a==="float")return isNaN(Number(t))?(c(`[${s}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(a==="json")try{return JSON.parse(t),!0}catch(i){return c(`[${s}] Invalid JSON for attribute "${n}": ${i.message}. Fallback: ${e.fallback}.`),!1}return!0}function ce(e,t,n){for(const r in n){const[o,s,a]=n[r];Object.defineProperty(e,r,{get:function(){return o(t,s,a)},enumerable:!0,configurable:!0})}return e}function ue(e){const t={};for(const n in e){const r=e[n];if(!r||!r.prop)continue;let o=r.read;if(!o&&r.type)switch(r.type){case"enum":o=se(r.values,r.fallback);break;case"integer":o=oe;break;case"float":o=ae;break;case"boolean":o=F;break;case"list":o=ie;break;case"json":o=le;break;case"string":default:o=I;break}o||(o=I),t[r.prop]=[o,n,r.fallback]}return t}function de(e){const t={};for(const n in e){const r=e[n];r&&r.effect&&(t[n]=r.effect)}return Object.keys(t).length?t:null}function fe(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 k(e,t,n,r){if(e.nodeType!==1)return;const s=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",a=Array.from(e.querySelectorAll(s));e.matches&&e.matches(s)&&a.push(e);for(const c of a)if(!c[n]){window.lnCore._persistSink&&c.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(c,t);try{c[n]=new r(c)}catch(i){console.error("["+n+"] init failed",c,i)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function he(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function be(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 j(){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 we(e){const t=j(),n=e.observed||[];for(let r=0;r<n.length;r++){const o=n[r];t.byAttr.has(o)||t.byAttr.set(o,[]),t.byAttr.get(o).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const r in e.attributes){t.byDeclaredAttr.has(r)||t.byDeclaredAttr.set(r,[]);const o=t.byDeclaredAttr.get(r);o.some(s=>s.componentTag===e.componentTag)||o.push({spec:e.attributes[r],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const r=fe(e);if(r===null)t.reactiveWildcard.push(e);else for(const o of r)t.byReactive.has(o)||t.byReactive.set(o,[]),t.byReactive.get(o).push(e)}e.persist&&t.persist.push(e)}function B(e,t,n,r){for(let o=0;o<e.length;o++){const s=e[o];if(!t[s.attribute])continue;const a=s.effects&&s.effects[n];a?a(t,n,r):s.onAttrChange&&(!s.declared||s.declared.has(n))&&s.onAttrChange(t,n,r)}}function pe(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const r=j(),o=r.byAttr.get(n);if(K()&&r.byDeclaredAttr&&r.byDeclaredAttr.has(n)&&A(t)){const s=r.byDeclaredAttr.get(n),a=t.getAttribute(n);for(let c=0;c<s.length;c++)M(s[c].spec,a,n,s[c].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||o)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const s=r.byReactive.get(n);s&&B(s,t,n,e.oldValue),r.reactiveWildcard.length&&B(r.reactiveWildcard,t,n,e.oldValue)}if(o)for(let s=0;s<o.length;s++){const a=o[s];if(a.handler){a.handler(t,n,e.oldValue);continue}a.onAttributeChange&&t[a.attribute]?a.onAttributeChange(t,n):(k(t,a.selector,a.attribute,a.ComponentFn),a.onInit&&a.onInit(t))}}function ge(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,m(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{pe(t[n])}catch(r){console.error("[ln-core] mutation handler failed",t[n].target,r)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function H(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function me(e){const t=H();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const r=t[n];if(r.onSubtreeChange){const o=r.query,s=e.target.nodeType===1?e.target.matches(o)?e.target:e.target.closest(o):e.target.parentElement?e.target.parentElement.closest(o):null;s&&r.onSubtreeChange(s,e)}}for(let n=0;n<e.addedNodes.length;n++){const r=e.addedNodes[n];if(r.nodeType===1)for(let o=0;o<t.length;o++){const s=t[o];k(r,s.selector,s.attribute,s.ComponentFn),s.onInit&&s.onInit(r)}}for(let n=0;n<e.removedNodes.length;n++){const r=e.removedNodes[n];if(r.nodeType===1)for(let o=0;o<t.length;o++){const s=t[o],a=s.query,c=Array.from(r.querySelectorAll(a));r.matches&&r.matches(a)&&c.push(r);for(let i=0;i<c.length;i++){const u=c[i];if(!document.contains(u)){const d=u[s.attribute];if(d&&typeof d.destroy=="function")try{d.destroy()}catch(l){console.error("["+s.attribute+"] destroy failed",u,l)}delete u[s.attribute]}}}}}}function ye(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,m(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const r=t[n];if(r.type==="childList")try{me(r)}catch(o){console.error("[ln-core] lifecycle handler failed",r.target,o)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function Ce(e,t,n,r,o={}){const s=o.extraAttributes||[],a=o.onAttributeChange||null,c=o.onSubtreeChange||null,i=o.onInit||null,u=o.onAttrChange||null,d=o.effects||null,l=o.attributes||null,f=l?de(l):d,b=l?new Set(Object.keys(l)):null,C=o.persist||null;function h(E){const w=E||document.body;if(k(w,e,t,n),l&&K())for(const g in l){const Ee=l[g],T=Array.from(w.querySelectorAll("["+g+"]"));w.matches&&w.matches("["+g+"]")&&T.push(w);for(let O=0;O<T.length;O++){const x=T[O];A(x)&&M(Ee,x.getAttribute(g),g,r,x)}}i&&i(w)}const L=[];if(e.indexOf("[")!==-1){const E=/\[([\w-]+)/g;let w;for(;(w=E.exec(e))!==null;)L.push(w[1])}else L.push(e);we({selector:e,attribute:t,componentTag:r,attributes:l,ComponentFn:n,onInit:i,observed:L.concat(s),onAttributeChange:a,onAttrChange:u,effects:f,declared:b,persist:C}),ge();const Le=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";H().push({selector:e,attribute:t,ComponentFn:n,onInit:i,onSubtreeChange:c,query:Le}),ye(),window[t]=h;function J(){he()>0?be(function(){h(document.body)}):h(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",J):J(),h}function W(e){return(e||"").replace(/^#/,"")}function S(e){const t=e===void 0?location.hash:e,n={},r=W(t);if(!r)return n;const o=r.split("&");for(let s=0;s<o.length;s++){const a=o[s];if(!a)continue;const c=a.indexOf(":"),i=c>-1?a.slice(0,c):a,u=c>-1?a.slice(c+1):"";if(i)try{n[i]=decodeURIComponent(u)}catch{n[i]=u}}return n}function p(e){if(!e)return null;const t=S();return e in t?t[e]:null}function y(e,t){if(!e)return;const n=S();t==null?delete n[e]:n[e]=String(t);const o=Object.keys(n).map(function(s){const a=n[s];return a===""?s:s+":"+encodeURIComponent(a)}).join("&");W(location.hash)!==o&&(location.hash=o)}function P(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Ae(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 r=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return r?t?r+"-"+t:r:t||null}function ve(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function _e(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 Se(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),r=e.slice(t+1),o=r?r.split(",").map(function(s){try{return decodeURIComponent(s)}catch{return s}}).filter(Boolean):[];return{key:n,values:o}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=S,window.lnCore.hashGet=p,window.lnCore.hashSet=y,window.lnCore.hashLinkClick=P,window.lnCore.resolveHashNamespace=Ae,window.lnCore.hashSortEncode=ve,window.lnCore.hashSortDecode=_e,window.lnCore.hashFilterEncode=ke,window.lnCore.hashFilterDecode=Se);function V(e,t,n,r){const o=(e||"").toLowerCase().trim();if(o)return o;if((t||"").toUpperCase()!=="A")return"";const s=n||"";if(!s.startsWith("#"))return"";const a=s.slice(1);if(!a)return"";const c=a.split("&"),i=(r||"").toLowerCase().trim();if(i)for(const l of c){const f=l.indexOf(":");if(f>0&&l.slice(0,f).toLowerCase().trim()===i)return l.slice(f+1).toLowerCase().trim()}const u=c[c.length-1]||"",d=u.indexOf(":");return(d>0?u.slice(d+1):u).toLowerCase().trim()}function U(e,t){if(!Array.isArray(e)||e.length===0)return{hashEnabled:!1,warning:null};const n=e.filter(s=>(s.tagName||"").toUpperCase()==="A"&&(s.href||"").startsWith("#")),r=n.length>0&&n.length===e.length,o=(t||"").toLowerCase().trim();return n.length>0&&n.length!==e.length?{hashEnabled:!1,warning:"mixed"}:r&&!o?{hashEnabled:!1,warning:"missing-namespace"}:{hashEnabled:r&&!!o,warning:null}}function Q(e,t,n){const r=(e||"").toLowerCase().trim();return r&&Array.isArray(t)&&t.includes(r)?r:(n||"").toLowerCase().trim()}(function(){const e="data-ln-tabs",t="lnTabs";if(window[t]!==void 0&&window[t]!==null)return;function n(i){const u=i.getAttribute("data-ln-tabs-active");i[t]&&i[t]._applyActive(u)}function r(i,u){return(i.getAttribute(u)||i.id||"").toLowerCase().trim()}const o={"data-ln-tabs":{type:"marker",description:"Mounts lnTabs component instance on tabs container"},"data-ln-tabs-active":{effect:n,type:"string",description:"Active tab key identifier"},"data-ln-tabs-default":{type:"string",description:"Default fallback tab key when none selected"},"data-ln-tabs-focus":{prop:"autoFocus",read:F,type:"boolean",fallback:!0,description:"Whether to shift focus to newly activated tab panel"},"data-ln-tabs-key":{prop:"nsKey",read:r,type:"string",description:"Hash namespace key for URL hash synchronization"},"data-ln-tab":{type:"string",description:"Tab trigger key identifier"},"data-ln-panel":{type:"string",description:"Tab content panel key identifier matching corresponding tab"}},s=ue(o);function a(i){return this.dom=i,ce(this,i,s),this.activeKey=null,c.call(this),this}function c(){this.tabs=Array.from(this.dom.querySelectorAll("[data-ln-tab]")),this.panels=Array.from(this.dom.querySelectorAll("[data-ln-panel]"));const i=this.tabs.map(l=>({tagName:l.tagName,href:l.getAttribute("href")})),u=U(i,this.nsKey);this.hashEnabled=u.hashEnabled,u.warning==="mixed"?console.warn('[ln-tabs] Mixed <a href="#…"> and <button> triggers in one group — using persist mode. Pick one: anchors for URL hash, buttons for localStorage persist.',this.dom):u.warning==="missing-namespace"&&console.warn("[ln-tabs] Anchor triggers need a hash namespace — add id or data-ln-tabs-key to the wrapper. Falling back to non-hash mode.",this.dom),this.mapTabs={},this.mapPanels={};for(const l of this.tabs){const f=V(l.getAttribute("data-ln-tab"),l.tagName,l.getAttribute("href"),this.nsKey);f?this.mapTabs[f]=l:console.warn('[ln-tabs] Trigger has no resolvable key — needs `data-ln-tab="key"` or `<a href="#…">`.',l)}for(const l of this.panels){const f=(l.getAttribute("data-ln-panel")||"").toLowerCase().trim();f&&(this.mapPanels[f]=l)}this.defaultKey=(this.dom.getAttribute("data-ln-tabs-default")||"").toLowerCase().trim()||Object.keys(this.mapTabs)[0]||"";const d=this;this._clickHandlers=[];for(const l of this.tabs){if(l[t+"Trigger"])continue;const f=function(b){const C=l.tagName==="A";if(!C&&(b.ctrlKey||b.metaKey||b.button===1))return;const h=V(l.getAttribute("data-ln-tab"),l.tagName,l.getAttribute("href"),d.nsKey);h&&(C&&!P(b)||(d.hashEnabled?p(d.nsKey)===h?d.dom.setAttribute("data-ln-tabs-active",h):y(d.nsKey,h):d.dom.setAttribute("data-ln-tabs-active",h)))};l.addEventListener("click",f),l[t+"Trigger"]=f,d._clickHandlers.push({el:l,handler:f})}if(this._onRequestSelect=function(l){const f=l.detail&&(l.detail.key||l.detail.tab);f&&d.select(f)},this.dom.addEventListener("ln-tabs:request-select",this._onRequestSelect),this._hashHandler=function(){if(!d.hashEnabled)return;const l=p(d.nsKey);d.dom.setAttribute("data-ln-tabs-active",l!==null?l:d.defaultKey)},this.hashEnabled)window.addEventListener("hashchange",this._hashHandler),this._hashHandler();else{const l=Q(this.dom.getAttribute("data-ln-tabs-active"),Object.keys(this.mapPanels),this.defaultKey);this.dom.setAttribute("data-ln-tabs-active",l)}}a.prototype.select=function(i){const u=(i+"").toLowerCase().trim();u&&(this.hashEnabled?p(this.nsKey)===u?this.dom.setAttribute("data-ln-tabs-active",u):y(this.nsKey,u):this.dom.setAttribute("data-ln-tabs-active",u))},a.prototype._applyActive=function(i){var d;if(i=Q(i,Object.keys(this.mapPanels),this.defaultKey),i===this.activeKey)return;const u=this.activeKey;if(u!==null&&z(this.dom,"ln-tabs:before-change",{key:i,previousKey:u,tab:this.mapTabs[i],panel:this.mapPanels[i],target:this.dom}).defaultPrevented){u in this.mapPanels&&(this.dom.setAttribute("data-ln-tabs-active",u),this.hashEnabled&&p(this.nsKey)!==u&&y(this.nsKey,u));return}this.activeKey=i;for(const l in this.mapTabs){const f=this.mapTabs[l];l===i?(f.setAttribute("data-active",""),f.setAttribute("aria-selected","true")):(f.removeAttribute("data-active"),f.setAttribute("aria-selected","false"))}for(const l in this.mapPanels){const f=this.mapPanels[l],b=l===i;f.classList.toggle("hidden",!b),f.setAttribute("aria-hidden",b?"false":"true")}if(this.autoFocus){const l=(d=this.mapPanels[i])==null?void 0:d.querySelector('input,button,select,textarea,[tabindex]:not([tabindex="-1"])');l&&setTimeout(()=>l.focus({preventScroll:!0}),0)}q(this.dom,"ln-tabs:change",{key:i,previousKey:u,tab:this.mapTabs[i],panel:this.mapPanels[i],target:this.dom})},a.prototype.destroy=function(){if(this.dom[t]){this.dom.removeEventListener("ln-tabs:request-select",this._onRequestSelect);for(const{el:i,handler:u}of this._clickHandlers)i.removeEventListener("click",u),delete i[t+"Trigger"];this.hashEnabled&&window.removeEventListener("hashchange",this._hashHandler),delete this.dom[t]}},Ce(e,t,a,"ln-tabs",{attributes:o,persist:{attr:"data-ln-tabs-active",hashActive:function(i){const u=Array.from(i.querySelectorAll("[data-ln-tab]")).map(function(l){return{tagName:l.tagName,href:l.getAttribute("href")}}),d=(i.getAttribute("data-ln-tabs-key")||i.id||"").toLowerCase().trim();return U(u,d).hashEnabled}}})})()})();
|
|
@@ -0,0 +1,75 @@
|
|
|
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-tabs",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {
|
|
6
|
+
"data-ln-debug": {
|
|
7
|
+
"direction": null,
|
|
8
|
+
"sources": [
|
|
9
|
+
"ln-tabs-dev.scss"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"data-ln-panel": {
|
|
13
|
+
"direction": "author",
|
|
14
|
+
"sources": [
|
|
15
|
+
"ln-tabs.scss",
|
|
16
|
+
"src/ln-tabs.js"
|
|
17
|
+
],
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Tab content panel key identifier matching corresponding tab"
|
|
20
|
+
},
|
|
21
|
+
"data-ln-tab": {
|
|
22
|
+
"direction": "author",
|
|
23
|
+
"sources": [
|
|
24
|
+
"ln-tabs-dev.scss",
|
|
25
|
+
"src/ln-tabs.js"
|
|
26
|
+
],
|
|
27
|
+
"type": "string",
|
|
28
|
+
"description": "Tab trigger key identifier"
|
|
29
|
+
},
|
|
30
|
+
"data-ln-tabs": {
|
|
31
|
+
"direction": null,
|
|
32
|
+
"sources": [
|
|
33
|
+
"ln-tabs-dev.scss",
|
|
34
|
+
"ln-tabs.scss",
|
|
35
|
+
"src/ln-tabs.js"
|
|
36
|
+
],
|
|
37
|
+
"type": "marker",
|
|
38
|
+
"description": "Mounts lnTabs component instance on tabs container"
|
|
39
|
+
},
|
|
40
|
+
"data-ln-tabs-active": {
|
|
41
|
+
"direction": "both",
|
|
42
|
+
"sources": [
|
|
43
|
+
"src/ln-tabs.js"
|
|
44
|
+
],
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Active tab key identifier"
|
|
47
|
+
},
|
|
48
|
+
"data-ln-tabs-default": {
|
|
49
|
+
"direction": "author",
|
|
50
|
+
"sources": [
|
|
51
|
+
"src/ln-tabs.js"
|
|
52
|
+
],
|
|
53
|
+
"type": "string",
|
|
54
|
+
"description": "Default fallback tab key when none selected"
|
|
55
|
+
},
|
|
56
|
+
"data-ln-tabs-focus": {
|
|
57
|
+
"direction": null,
|
|
58
|
+
"sources": [
|
|
59
|
+
"src/ln-tabs.js"
|
|
60
|
+
],
|
|
61
|
+
"type": "boolean",
|
|
62
|
+
"fallback": true,
|
|
63
|
+
"description": "Whether to shift focus to newly activated tab panel"
|
|
64
|
+
},
|
|
65
|
+
"data-ln-tabs-key": {
|
|
66
|
+
"direction": "author",
|
|
67
|
+
"sources": [
|
|
68
|
+
"ln-tabs-dev.scss",
|
|
69
|
+
"src/ln-tabs.js"
|
|
70
|
+
],
|
|
71
|
+
"type": "string",
|
|
72
|
+
"description": "Hash namespace key for URL hash synchronization"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// ==========================================================================
|
|
2
|
+
// ln-tabs — Functional Panel State
|
|
3
|
+
// ==========================================================================
|
|
4
|
+
|
|
5
|
+
[data-ln-tabs] [data-ln-panel].hidden,
|
|
6
|
+
[data-ln-tabs] [data-ln-panel][aria-hidden="true"] {
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/* Live Networks - lnTabs (hash-aware tabs — supports <button> and <a href="#nsKey:key"> triggers) */
|
|
2
|
+
import { dispatch, dispatchCancelable, hashGet, hashLinkClick, hashSet, registerComponent, attrSpec, defineAttrs, attrBool } from '../../ln-core';
|
|
3
|
+
import { deriveKeyFromTrigger, determineTabsMode, resolveActiveTabKey } from './tabs-model.js';
|
|
4
|
+
|
|
5
|
+
(function () {
|
|
6
|
+
const DOM_SELECTOR = "data-ln-tabs";
|
|
7
|
+
const DOM_ATTRIBUTE = "lnTabs";
|
|
8
|
+
|
|
9
|
+
if (window[DOM_ATTRIBUTE] !== undefined && window[DOM_ATTRIBUTE] !== null) return;
|
|
10
|
+
|
|
11
|
+
function _syncActive(el) {
|
|
12
|
+
const key = el.getAttribute('data-ln-tabs-active');
|
|
13
|
+
if (el[DOM_ATTRIBUTE]) el[DOM_ATTRIBUTE]._applyActive(key);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function _readTabsKey(el, name) { return (el.getAttribute(name) || el.id || '').toLowerCase().trim(); }
|
|
17
|
+
|
|
18
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
19
|
+
const ATTRIBUTES = {
|
|
20
|
+
'data-ln-tabs': { type: 'marker', description: 'Mounts lnTabs component instance on tabs container' },
|
|
21
|
+
'data-ln-tabs-active': { effect: _syncActive, type: 'string', description: 'Active tab key identifier' },
|
|
22
|
+
'data-ln-tabs-default': { type: 'string', description: 'Default fallback tab key when none selected' },
|
|
23
|
+
'data-ln-tabs-focus': { prop: 'autoFocus', read: attrBool, type: 'boolean', fallback: true, description: 'Whether to shift focus to newly activated tab panel' },
|
|
24
|
+
'data-ln-tabs-key': { prop: 'nsKey', read: _readTabsKey, type: 'string', description: 'Hash namespace key for URL hash synchronization' },
|
|
25
|
+
'data-ln-tab': { type: 'string', description: 'Tab trigger key identifier' },
|
|
26
|
+
'data-ln-panel': { type: 'string', description: 'Tab content panel key identifier matching corresponding tab' }
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const ATTR_SPEC = attrSpec(ATTRIBUTES);
|
|
30
|
+
|
|
31
|
+
function _component(dom) { this.dom = dom; defineAttrs(this, dom, ATTR_SPEC); this.activeKey = null; _init.call(this); return this; }
|
|
32
|
+
|
|
33
|
+
function _init() {
|
|
34
|
+
this.tabs = Array.from(this.dom.querySelectorAll("[data-ln-tab]"));
|
|
35
|
+
this.panels = Array.from(this.dom.querySelectorAll("[data-ln-panel]"));
|
|
36
|
+
|
|
37
|
+
const triggerDescriptors = this.tabs.map(t => ({
|
|
38
|
+
tagName: t.tagName,
|
|
39
|
+
href: t.getAttribute('href')
|
|
40
|
+
}));
|
|
41
|
+
const modeInfo = determineTabsMode(triggerDescriptors, this.nsKey);
|
|
42
|
+
this.hashEnabled = modeInfo.hashEnabled;
|
|
43
|
+
|
|
44
|
+
if (modeInfo.warning === 'mixed') {
|
|
45
|
+
console.warn('[ln-tabs] Mixed <a href="#…"> and <button> triggers in one group — using persist mode. Pick one: anchors for URL hash, buttons for localStorage persist.', this.dom);
|
|
46
|
+
} else if (modeInfo.warning === 'missing-namespace') {
|
|
47
|
+
console.warn('[ln-tabs] Anchor triggers need a hash namespace — add id or data-ln-tabs-key to the wrapper. Falling back to non-hash mode.', this.dom);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.mapTabs = {};
|
|
51
|
+
this.mapPanels = {};
|
|
52
|
+
for (const t of this.tabs) {
|
|
53
|
+
const key = deriveKeyFromTrigger(t.getAttribute('data-ln-tab'), t.tagName, t.getAttribute('href'), this.nsKey);
|
|
54
|
+
if (key) {
|
|
55
|
+
this.mapTabs[key] = t;
|
|
56
|
+
} else {
|
|
57
|
+
console.warn('[ln-tabs] Trigger has no resolvable key — needs `data-ln-tab="key"` or `<a href="#…">`.', t);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const p of this.panels) {
|
|
61
|
+
const key = (p.getAttribute("data-ln-panel") || "").toLowerCase().trim();
|
|
62
|
+
if (key) this.mapPanels[key] = p;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Not a pure attribute mirror: falls back to the first tab key, which
|
|
66
|
+
// only exists once mapTabs is built. A reader cannot reach instance state.
|
|
67
|
+
this.defaultKey = (this.dom.getAttribute("data-ln-tabs-default") || "").toLowerCase().trim()
|
|
68
|
+
|| Object.keys(this.mapTabs)[0] || "";
|
|
69
|
+
|
|
70
|
+
const self = this;
|
|
71
|
+
this._clickHandlers = [];
|
|
72
|
+
for (const t of this.tabs) {
|
|
73
|
+
if (t[DOM_ATTRIBUTE + 'Trigger']) continue;
|
|
74
|
+
const handler = function (e) {
|
|
75
|
+
const isAnchor = t.tagName === "A";
|
|
76
|
+
if (!isAnchor && (e.ctrlKey || e.metaKey || e.button === 1)) return;
|
|
77
|
+
const key = deriveKeyFromTrigger(t.getAttribute('data-ln-tab'), t.tagName, t.getAttribute('href'), self.nsKey);
|
|
78
|
+
if (!key) return;
|
|
79
|
+
if (isAnchor && !hashLinkClick(e)) return;
|
|
80
|
+
if (self.hashEnabled) {
|
|
81
|
+
if (hashGet(self.nsKey) === key) self.dom.setAttribute('data-ln-tabs-active', key);
|
|
82
|
+
else hashSet(self.nsKey, key);
|
|
83
|
+
} else {
|
|
84
|
+
self.dom.setAttribute('data-ln-tabs-active', key);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
t.addEventListener("click", handler);
|
|
88
|
+
t[DOM_ATTRIBUTE + 'Trigger'] = handler;
|
|
89
|
+
self._clickHandlers.push({ el: t, handler: handler });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this._onRequestSelect = function (e) {
|
|
93
|
+
const key = e.detail && (e.detail.key || e.detail.tab);
|
|
94
|
+
if (key) self.select(key);
|
|
95
|
+
};
|
|
96
|
+
this.dom.addEventListener('ln-tabs:request-select', this._onRequestSelect);
|
|
97
|
+
|
|
98
|
+
this._hashHandler = function () {
|
|
99
|
+
if (!self.hashEnabled) return;
|
|
100
|
+
const val = hashGet(self.nsKey);
|
|
101
|
+
self.dom.setAttribute('data-ln-tabs-active', val !== null ? val : self.defaultKey);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (this.hashEnabled) {
|
|
105
|
+
window.addEventListener("hashchange", this._hashHandler);
|
|
106
|
+
this._hashHandler();
|
|
107
|
+
} else {
|
|
108
|
+
const initialKey = resolveActiveTabKey(this.dom.getAttribute('data-ln-tabs-active'), Object.keys(this.mapPanels), this.defaultKey);
|
|
109
|
+
this.dom.setAttribute('data-ln-tabs-active', initialKey);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_component.prototype.select = function (key) {
|
|
114
|
+
const k = (key + '').toLowerCase().trim();
|
|
115
|
+
if (!k) return;
|
|
116
|
+
if (this.hashEnabled) {
|
|
117
|
+
if (hashGet(this.nsKey) === k) this.dom.setAttribute('data-ln-tabs-active', k);
|
|
118
|
+
else hashSet(this.nsKey, k);
|
|
119
|
+
} else {
|
|
120
|
+
this.dom.setAttribute('data-ln-tabs-active', k);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
_component.prototype._applyActive = function (key) {
|
|
125
|
+
key = resolveActiveTabKey(key, Object.keys(this.mapPanels), this.defaultKey);
|
|
126
|
+
if (key === this.activeKey) return;
|
|
127
|
+
|
|
128
|
+
const prevKey = this.activeKey;
|
|
129
|
+
if (prevKey !== null) {
|
|
130
|
+
const before = dispatchCancelable(this.dom, 'ln-tabs:before-change', {
|
|
131
|
+
key: key,
|
|
132
|
+
previousKey: prevKey,
|
|
133
|
+
tab: this.mapTabs[key],
|
|
134
|
+
panel: this.mapPanels[key],
|
|
135
|
+
target: this.dom
|
|
136
|
+
});
|
|
137
|
+
if (before.defaultPrevented) {
|
|
138
|
+
if (prevKey in this.mapPanels) {
|
|
139
|
+
this.dom.setAttribute('data-ln-tabs-active', prevKey);
|
|
140
|
+
if (this.hashEnabled && hashGet(this.nsKey) !== prevKey) {
|
|
141
|
+
hashSet(this.nsKey, prevKey);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.activeKey = key;
|
|
149
|
+
|
|
150
|
+
for (const k in this.mapTabs) {
|
|
151
|
+
const btn = this.mapTabs[k];
|
|
152
|
+
if (k === key) {
|
|
153
|
+
btn.setAttribute("data-active", "");
|
|
154
|
+
btn.setAttribute("aria-selected", "true");
|
|
155
|
+
} else {
|
|
156
|
+
btn.removeAttribute("data-active");
|
|
157
|
+
btn.setAttribute("aria-selected", "false");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (const k in this.mapPanels) {
|
|
161
|
+
const panel = this.mapPanels[k];
|
|
162
|
+
const show = (k === key);
|
|
163
|
+
panel.classList.toggle("hidden", !show);
|
|
164
|
+
panel.setAttribute("aria-hidden", show ? "false" : "true");
|
|
165
|
+
}
|
|
166
|
+
if (this.autoFocus) {
|
|
167
|
+
const first = this.mapPanels[key]?.querySelector('input,button,select,textarea,[tabindex]:not([tabindex="-1"])');
|
|
168
|
+
if (first) setTimeout(() => first.focus({ preventScroll: true }), 0);
|
|
169
|
+
}
|
|
170
|
+
dispatch(this.dom, 'ln-tabs:change', {
|
|
171
|
+
key: key,
|
|
172
|
+
previousKey: prevKey,
|
|
173
|
+
tab: this.mapTabs[key],
|
|
174
|
+
panel: this.mapPanels[key],
|
|
175
|
+
target: this.dom
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
_component.prototype.destroy = function () {
|
|
180
|
+
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
181
|
+
this.dom.removeEventListener('ln-tabs:request-select', this._onRequestSelect);
|
|
182
|
+
for (const { el, handler } of this._clickHandlers) {
|
|
183
|
+
el.removeEventListener("click", handler);
|
|
184
|
+
delete el[DOM_ATTRIBUTE + 'Trigger'];
|
|
185
|
+
}
|
|
186
|
+
if (this.hashEnabled) {
|
|
187
|
+
window.removeEventListener("hashchange", this._hashHandler);
|
|
188
|
+
}
|
|
189
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// ─── Init ──────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-tabs', {
|
|
195
|
+
attributes: ATTRIBUTES,
|
|
196
|
+
persist: {
|
|
197
|
+
attr: 'data-ln-tabs-active',
|
|
198
|
+
hashActive: function (el) {
|
|
199
|
+
const triggers = Array.from(el.querySelectorAll('[data-ln-tab]')).map(function (t) {
|
|
200
|
+
return { tagName: t.tagName, href: t.getAttribute('href') };
|
|
201
|
+
});
|
|
202
|
+
const nsKey = (el.getAttribute('data-ln-tabs-key') || el.id || '').toLowerCase().trim();
|
|
203
|
+
return determineTabsMode(triggers, nsKey).hashEnabled;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
})();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derives a tab key from an explicit attribute or anchor href hash fragment.
|
|
3
|
+
* @param {string|null} explicitTabAttr
|
|
4
|
+
* @param {string} tagName
|
|
5
|
+
* @param {string|null} href
|
|
6
|
+
* @param {string|null} [nsKey]
|
|
7
|
+
* @returns {string}
|
|
8
|
+
*/
|
|
9
|
+
export function deriveKeyFromTrigger(explicitTabAttr, tagName, href, nsKey) {
|
|
10
|
+
const explicit = (explicitTabAttr || '').toLowerCase().trim();
|
|
11
|
+
if (explicit) return explicit;
|
|
12
|
+
|
|
13
|
+
if ((tagName || '').toUpperCase() !== 'A') return '';
|
|
14
|
+
|
|
15
|
+
const rawHref = href || '';
|
|
16
|
+
if (!rawHref.startsWith('#')) return '';
|
|
17
|
+
|
|
18
|
+
const raw = rawHref.slice(1);
|
|
19
|
+
if (!raw) return '';
|
|
20
|
+
|
|
21
|
+
const fragments = raw.split('&');
|
|
22
|
+
const normalizedNs = (nsKey || '').toLowerCase().trim();
|
|
23
|
+
|
|
24
|
+
if (normalizedNs) {
|
|
25
|
+
for (const frag of fragments) {
|
|
26
|
+
const sep = frag.indexOf(':');
|
|
27
|
+
if (sep > 0 && frag.slice(0, sep).toLowerCase().trim() === normalizedNs) {
|
|
28
|
+
return frag.slice(sep + 1).toLowerCase().trim();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const last = fragments[fragments.length - 1] || '';
|
|
34
|
+
const sep = last.indexOf(':');
|
|
35
|
+
return (sep > 0 ? last.slice(sep + 1) : last).toLowerCase().trim();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Determines whether tabs should use URL hash sync mode or local persist mode.
|
|
40
|
+
* @param {Array<{ tagName: string, href?: string|null }>} triggers
|
|
41
|
+
* @param {string|null} nsKey
|
|
42
|
+
* @returns {{ hashEnabled: boolean, warning: 'mixed' | 'missing-namespace' | null }}
|
|
43
|
+
*/
|
|
44
|
+
export function determineTabsMode(triggers, nsKey) {
|
|
45
|
+
if (!Array.isArray(triggers) || triggers.length === 0) {
|
|
46
|
+
return { hashEnabled: false, warning: null };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const anchorTabs = triggers.filter(
|
|
50
|
+
t => (t.tagName || '').toUpperCase() === 'A' && (t.href || '').startsWith('#')
|
|
51
|
+
);
|
|
52
|
+
const allAnchors = anchorTabs.length > 0 && anchorTabs.length === triggers.length;
|
|
53
|
+
const normalizedNs = (nsKey || '').toLowerCase().trim();
|
|
54
|
+
|
|
55
|
+
if (anchorTabs.length > 0 && anchorTabs.length !== triggers.length) {
|
|
56
|
+
return { hashEnabled: false, warning: 'mixed' };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (allAnchors && !normalizedNs) {
|
|
60
|
+
return { hashEnabled: false, warning: 'missing-namespace' };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
hashEnabled: allAnchors && Boolean(normalizedNs),
|
|
65
|
+
warning: null
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolves the valid active key against registered panel keys with fallback.
|
|
71
|
+
* @param {string|null} requestedKey
|
|
72
|
+
* @param {string[]} validPanelKeys
|
|
73
|
+
* @param {string} defaultKey
|
|
74
|
+
* @returns {string}
|
|
75
|
+
*/
|
|
76
|
+
export function resolveActiveTabKey(requestedKey, validPanelKeys, defaultKey) {
|
|
77
|
+
const key = (requestedKey || '').toLowerCase().trim();
|
|
78
|
+
if (key && Array.isArray(validPanelKeys) && validPanelKeys.includes(key)) {
|
|
79
|
+
return key;
|
|
80
|
+
}
|
|
81
|
+
return (defaultKey || '').toLowerCase().trim();
|
|
82
|
+
}
|
|
@@ -1,95 +1,96 @@
|
|
|
1
|
-
# ln-time
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
| `< 60
|
|
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
|
-
|
|
1
|
+
# ln-time
|
|
2
|
+
|
|
3
|
+
> Applied to a `<time data-ln-time="..." datetime="...">` element where `datetime` holds a Unix timestamp in seconds.
|
|
4
|
+
> On initialization and on attribute mutation, it formats the timestamp using browser `Intl.DateTimeFormat` or `Intl.RelativeTimeFormat`
|
|
5
|
+
> and writes the localized string to `time.textContent`. When set to `relative`, a shared 60-second timer periodically recalculates
|
|
6
|
+
> and updates `textContent` without polling the server.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 🧭 Philosophy & Architecture
|
|
11
|
+
|
|
12
|
+
1. **Progressive Enhancement:** Server layouts (e.g. Laravel Blade templates) render standard text fallbacks inside native `<time>` elements. If JavaScript fails or is blocked, the original text is preserved; when active, the component compiles and overwrites it.
|
|
13
|
+
2. **Standard-Based API Concurrency:** Built entirely on standard browser APIs (`Intl.DateTimeFormat` and `Intl.RelativeTimeFormat`). It bypasses heavy date-parsing libraries, leveraging the browser's native locale and timezone mappings.
|
|
14
|
+
3. **Shared Interval Loop:** Dynamic relative timestamps (e.g., "5 minutes ago") auto-update every 60 seconds. Instead of spinning up individual intervals, a single global interval manager coordinates all active elements, automatically purging detached nodes.
|
|
15
|
+
4. **Reactive State Resolution:** All state changes are governed by native HTML attributes. Changing `datetime` or `data-ln-time` triggers automatic DOM re-renders via `MutationObserver` synchronization.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 📦 Minimal Blueprint
|
|
20
|
+
|
|
21
|
+
### Static Localized Date
|
|
22
|
+
Provide a Unix timestamp (in seconds) via `datetime` and specify the formatting mode.
|
|
23
|
+
```html
|
|
24
|
+
<!-- Server renders a fallback, JS enhances with user timezone and locale -->
|
|
25
|
+
<time data-ln-time="full" datetime="1736952600">January 15, 2025</time>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Auto-Updating Relative Timestamp
|
|
29
|
+
```html
|
|
30
|
+
<!-- Automatically updates every 60s (e.g. "3 minutes ago") -->
|
|
31
|
+
<time data-ln-time="relative" datetime="1736952600">Jan 15</time>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Custom Localized Override
|
|
35
|
+
```html
|
|
36
|
+
<!-- Localizes the time string to Macedonian regardless of browser defaults -->
|
|
37
|
+
<time data-ln-time="full" datetime="1736952600" data-ln-time-locale="mk">Јануари 15, 2025</time>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🛠️ Declarative API Contract
|
|
43
|
+
|
|
44
|
+
### HTML Attributes
|
|
45
|
+
|
|
46
|
+
| Attribute | Elements | Description |
|
|
47
|
+
| :--- | :--- | :--- |
|
|
48
|
+
| `data-ln-time` | `<time>` | Format mode: `relative`, `short`, `full`, `date`, `time`. |
|
|
49
|
+
| `datetime` | `<time>` | **Required**. Unix timestamp in **seconds**. Milliseconds and ISO 8601 strings are also read (via `ln-core`'s `parseDateInput`). |
|
|
50
|
+
| `data-ln-time-locale`| `<time>` | Opt-in. Force-overrides translation locale (e.g. `"de"`, `"mk"`). |
|
|
51
|
+
|
|
52
|
+
### Format Modes
|
|
53
|
+
|
|
54
|
+
| Mode | Output Example | Intl Engine |
|
|
55
|
+
| :--- | :--- | :--- |
|
|
56
|
+
| `relative` | `"3 hr. ago"`, `"just now"`, `"in 2 hr."` | `Intl.RelativeTimeFormat` |
|
|
57
|
+
| `short` | `"Jan 15"` (current year) / `"Jan 15, 2024"` | `{ month: 'short', day: 'numeric' }` |
|
|
58
|
+
| `full` | `"January 15, 2025 at 2:30 PM"` | `{ dateStyle: 'long', timeStyle: 'short' }` |
|
|
59
|
+
| `date` | `"Jan 15, 2025"` | `{ dateStyle: 'medium' }` |
|
|
60
|
+
| `time` | `"2:30 PM"` | `{ timeStyle: 'short' }` |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## ⚡ Live Relative Thresholds
|
|
65
|
+
|
|
66
|
+
| Elapsed Time | Evaluated Unit | Output Example (English) |
|
|
67
|
+
| :--- | :--- | :--- |
|
|
68
|
+
| `< 10 seconds` | — | `"now"` |
|
|
69
|
+
| `< 60 seconds` | `second` | `"45 sec. ago"` |
|
|
70
|
+
| `< 60 minutes` | `minute` | `"5 min. ago"` |
|
|
71
|
+
| `< 24 hours` | `hour` | `"3 hr. ago"` |
|
|
72
|
+
| `< 7 days` | `day` | `"2 days ago"` |
|
|
73
|
+
| `< 30 days` | `week` | `"2 wk. ago"` |
|
|
74
|
+
| `>= 30 days` | — | Falls back to static `short` date. |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## ⚠️ Common Pitfalls
|
|
79
|
+
|
|
80
|
+
- **Seconds vs milliseconds is decided by magnitude:** a value ≥ 10¹¹ is read as milliseconds, smaller as seconds, so `1736952600` and `1736952600000` render the same instant.
|
|
81
|
+
- **Date-only ISO is local:** `datetime="2025-01-15"` is local midnight of that day; a full timestamp (`2025-01-15T14:30:00Z`) is that exact instant.
|
|
82
|
+
- **Empty `datetime` Attributes:** If the `datetime` attribute is omitted or empty, the component will skip formatting to preserve server fallback strings.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 🔧 Internals
|
|
87
|
+
|
|
88
|
+
Source: `components/ln-time/ln-time.js`. Registers via `ln-core`'s `registerComponent` with `extraAttributes: ['datetime']` — the shared observer treats mutations to `datetime` (not just `data-ln-time`) as a re-render trigger, so swapping the timestamp on an existing element re-formats it without a manual re-init call.
|
|
89
|
+
|
|
90
|
+
### Shared interval
|
|
91
|
+
|
|
92
|
+
All `relative`-mode elements auto-refresh off a single shared `setInterval` (60s), not one timer per element. The interval starts lazily on the first relative element and stops when the last one is gone; elements removed from the DOM without calling `destroy()` are purged from the pool automatically on the next tick rather than leaking.
|
|
93
|
+
|
|
94
|
+
### Dependencies
|
|
95
|
+
|
|
96
|
+
Built entirely on `Intl.DateTimeFormat` and `Intl.RelativeTimeFormat` (both browser built-ins) — no date-parsing library, no polyfill.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@use '../../theme/config/mixins' as *;
|
|
2
|
+
|
|
3
|
+
[data-ln-debug] {
|
|
4
|
+
// 1. Host Element Check: data-ln-time belongs on native <time> elements
|
|
5
|
+
[data-ln-time]:not(time) {
|
|
6
|
+
@include dev-inline-error("data-ln-time belongs on native <time> elements");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// 2. Datetime Attribute Check: <time data-ln-time> requires a datetime attribute
|
|
10
|
+
time[data-ln-time]:not([datetime]) {
|
|
11
|
+
@include dev-inline-error("<time data-ln-time> is missing required datetime attribute");
|
|
12
|
+
}
|
|
13
|
+
}
|