@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,321 @@
|
|
|
1
|
+
import { compareValues, detectValueType, dispatchCancelable, getLocale, hashGet, hashSet, hashSortDecode, hashSortEncode, queueBoot, readValue, registerComponent, resolveHashNamespace, attrStr, attrSpec, defineAttrs } from '../../ln-core';
|
|
2
|
+
import { createSortComparator, getAriaSortValue, isExcludedSortItem, isSameSortTarget, normalizeSortDirection, resolveSortItems } from './sort-model.js';
|
|
3
|
+
|
|
4
|
+
(function () {
|
|
5
|
+
const DOM_SELECTOR = 'data-ln-sort';
|
|
6
|
+
const DOM_ATTRIBUTE = 'lnSort';
|
|
7
|
+
const FIELD_ATTR = 'data-ln-sort-field';
|
|
8
|
+
const STATE_ATTR = 'data-ln-sort-state';
|
|
9
|
+
const DIR_ATTR = 'data-ln-sort-dir';
|
|
10
|
+
const HASH_ATTR = 'data-ln-hash';
|
|
11
|
+
|
|
12
|
+
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
13
|
+
|
|
14
|
+
function _readOrNull(el, name) {
|
|
15
|
+
return el.getAttribute(name) || null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
19
|
+
const ATTRIBUTES = {
|
|
20
|
+
'data-ln-sort': { prop: 'targetId', type: 'string', read: attrStr, fallback: null, description: 'Target table or list element ID to sort' },
|
|
21
|
+
'data-ln-sort-field': { prop: 'field', type: 'string', read: _readOrNull, effect: _syncAttribute, description: 'Field name or column key to sort by' },
|
|
22
|
+
'data-ln-sort-dir': { type: 'enum', values: ['asc', 'desc'], fallback: 'asc', description: 'Default or requested sort direction' },
|
|
23
|
+
'data-ln-sort-items': { prop: 'itemsSelector', type: 'string', read: _readOrNull, description: 'CSS selector matching sortable child items' },
|
|
24
|
+
'data-ln-sort-state': { type: 'enum', values: ['asc', 'desc', 'none'], fallback: 'none', effect: _syncAttribute, description: 'Active sort state applied to column or control' },
|
|
25
|
+
'data-ln-hash': { type: 'string', effect: _syncAttribute, description: 'URL hash routing key for sort state persistence' }
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const ATTR_SPEC = attrSpec(ATTRIBUTES);
|
|
29
|
+
|
|
30
|
+
// Target-scoped initial DOM order cache.
|
|
31
|
+
const _targetInitialOrders = new WeakMap();
|
|
32
|
+
|
|
33
|
+
function _readItemValue(item, field, column) {
|
|
34
|
+
if (field) {
|
|
35
|
+
const el = item.querySelector('[data-ln-field="' + field + '"]');
|
|
36
|
+
return el ? readValue(el) : '';
|
|
37
|
+
}
|
|
38
|
+
if (column !== null && column !== undefined && item.cells && item.cells[column]) {
|
|
39
|
+
return readValue(item.cells[column]);
|
|
40
|
+
}
|
|
41
|
+
return readValue(item);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ─── Component ─────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
function _component(dom) {
|
|
47
|
+
this.dom = dom;
|
|
48
|
+
defineAttrs(this, dom, ATTR_SPEC);
|
|
49
|
+
|
|
50
|
+
const th = dom.closest('th');
|
|
51
|
+
this.column = (!this.field && th) ? th.cellIndex : null;
|
|
52
|
+
|
|
53
|
+
this._state = normalizeSortDirection(dom.getAttribute(STATE_ATTR));
|
|
54
|
+
if (!dom.hasAttribute(STATE_ATTR)) {
|
|
55
|
+
dom.setAttribute(STATE_ATTR, this._state);
|
|
56
|
+
}
|
|
57
|
+
this._destroyed = false;
|
|
58
|
+
|
|
59
|
+
this.nsKey = resolveHashNamespace(dom, 'sort');
|
|
60
|
+
this.hashEnabled = !!this.nsKey;
|
|
61
|
+
|
|
62
|
+
const self = this;
|
|
63
|
+
|
|
64
|
+
this._onClick = function (e) {
|
|
65
|
+
const btn = e.target.closest('[' + DIR_ATTR + ']');
|
|
66
|
+
if (!btn) return;
|
|
67
|
+
const nextDir = normalizeSortDirection(btn.getAttribute(DIR_ATTR));
|
|
68
|
+
self._apply(nextDir);
|
|
69
|
+
};
|
|
70
|
+
dom.addEventListener('click', this._onClick);
|
|
71
|
+
|
|
72
|
+
this._onSortChange = function (e) {
|
|
73
|
+
if (self._destroyed || !e.detail) return;
|
|
74
|
+
const target = self._resolveTarget();
|
|
75
|
+
const isOurTarget = (target && (e.target === target || target.contains(e.target)))
|
|
76
|
+
|| (e.detail.targetId && e.detail.targetId === self.targetId);
|
|
77
|
+
if (!isOurTarget) return;
|
|
78
|
+
|
|
79
|
+
const same = isSameSortTarget(
|
|
80
|
+
{ field: self.field, column: self.column },
|
|
81
|
+
{ field: e.detail.field, column: e.detail.column }
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (same) {
|
|
85
|
+
const nextDir = normalizeSortDirection(e.detail.direction);
|
|
86
|
+
if (nextDir && dom.getAttribute(STATE_ATTR) !== nextDir) {
|
|
87
|
+
self._state = nextDir;
|
|
88
|
+
dom.setAttribute(STATE_ATTR, nextDir);
|
|
89
|
+
self._updateAriaSort(nextDir);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Mutual exclusion: reset losing instances without re-dispatching
|
|
95
|
+
if (dom.getAttribute(STATE_ATTR) !== 'none') {
|
|
96
|
+
self._state = 'none';
|
|
97
|
+
dom.setAttribute(STATE_ATTR, 'none');
|
|
98
|
+
self._updateAriaSort('none');
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
document.addEventListener('ln-sort:change', this._onSortChange);
|
|
102
|
+
|
|
103
|
+
// ─── Hash change listener ──────────────────────────────────
|
|
104
|
+
this._onHashChange = function () {
|
|
105
|
+
if (self._destroyed || !self.hashEnabled) return;
|
|
106
|
+
const val = hashGet(self.nsKey);
|
|
107
|
+
const decoded = hashSortDecode(val);
|
|
108
|
+
if (decoded) {
|
|
109
|
+
const matches = (self.field !== null && decoded.fieldOrColumn === self.field)
|
|
110
|
+
|| (self.column !== null && String(self.column) === decoded.fieldOrColumn);
|
|
111
|
+
if (matches) {
|
|
112
|
+
if (self._state !== decoded.direction) self._apply(decoded.direction, true);
|
|
113
|
+
} else {
|
|
114
|
+
if (self._state !== 'none') {
|
|
115
|
+
self._state = 'none';
|
|
116
|
+
dom.setAttribute(STATE_ATTR, 'none');
|
|
117
|
+
self._updateAriaSort('none');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
if (self._state !== 'none') {
|
|
122
|
+
self._state = 'none';
|
|
123
|
+
dom.setAttribute(STATE_ATTR, 'none');
|
|
124
|
+
self._updateAriaSort('none');
|
|
125
|
+
const target = self._resolveTarget();
|
|
126
|
+
if (target) {
|
|
127
|
+
const evt = dispatchCancelable(target, 'ln-sort:change', {
|
|
128
|
+
field: self.field,
|
|
129
|
+
column: self.column,
|
|
130
|
+
direction: 'none',
|
|
131
|
+
targetId: self.targetId
|
|
132
|
+
});
|
|
133
|
+
if (!evt.defaultPrevented) self._defaultSort(target, 'none');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
if (this.hashEnabled) {
|
|
140
|
+
window.addEventListener('hashchange', this._onHashChange);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ─── Restore State on Boot ─────────────────────────────────
|
|
144
|
+
let restored = false;
|
|
145
|
+
|
|
146
|
+
if (this.hashEnabled) {
|
|
147
|
+
const hashVal = hashGet(this.nsKey);
|
|
148
|
+
const decoded = hashSortDecode(hashVal);
|
|
149
|
+
if (decoded) {
|
|
150
|
+
const matches = (self.field !== null && decoded.fieldOrColumn === self.field)
|
|
151
|
+
|| (self.column !== null && String(self.column) === decoded.fieldOrColumn);
|
|
152
|
+
if (matches) {
|
|
153
|
+
queueBoot(function () {
|
|
154
|
+
if (self._destroyed) return;
|
|
155
|
+
self._apply(decoded.direction, true);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
restored = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!restored) {
|
|
163
|
+
const initialDir = normalizeSortDirection(dom.getAttribute(STATE_ATTR));
|
|
164
|
+
if (initialDir && initialDir !== 'none') {
|
|
165
|
+
queueBoot(function () {
|
|
166
|
+
if (self._destroyed) return;
|
|
167
|
+
self._apply(initialDir, true);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_component.prototype._resolveTarget = function () {
|
|
176
|
+
return document.getElementById(this.targetId);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
_component.prototype._updateAriaSort = function (direction) {
|
|
180
|
+
const th = this.dom.closest('th');
|
|
181
|
+
if (!th) return;
|
|
182
|
+
th.setAttribute('aria-sort', getAriaSortValue(direction));
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
_component.prototype._apply = function (direction, skipStorage) {
|
|
186
|
+
if (this._destroyed) return;
|
|
187
|
+
if (!this.field && this.column === null) {
|
|
188
|
+
const th = this.dom.closest('th');
|
|
189
|
+
if (th && th.cellIndex !== undefined) this.column = th.cellIndex;
|
|
190
|
+
}
|
|
191
|
+
const normalized = normalizeSortDirection(direction);
|
|
192
|
+
this._state = normalized;
|
|
193
|
+
if (this.dom.getAttribute(STATE_ATTR) !== normalized) {
|
|
194
|
+
this.dom.setAttribute(STATE_ATTR, normalized);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
this._updateAriaSort(normalized);
|
|
198
|
+
|
|
199
|
+
const target = this._resolveTarget();
|
|
200
|
+
if (!target) return;
|
|
201
|
+
|
|
202
|
+
const detail = {
|
|
203
|
+
field: this.field,
|
|
204
|
+
column: this.column,
|
|
205
|
+
direction: normalized,
|
|
206
|
+
targetId: this.targetId
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
if (!skipStorage) {
|
|
210
|
+
if (this.hashEnabled) {
|
|
211
|
+
const encoded = hashSortEncode(this.field !== null ? this.field : this.column, normalized);
|
|
212
|
+
hashSet(this.nsKey, encoded);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const evt = dispatchCancelable(target, 'ln-sort:change', detail);
|
|
217
|
+
if (evt.defaultPrevented) return;
|
|
218
|
+
|
|
219
|
+
this._defaultSort(target, normalized);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// ─── Default DOM behaviour ─────────────────────────────────
|
|
223
|
+
|
|
224
|
+
_component.prototype._defaultSort = function (target, direction) {
|
|
225
|
+
const allItems = resolveSortItems(target, this.itemsSelector);
|
|
226
|
+
if (!allItems.length) return;
|
|
227
|
+
const parent = allItems[0].parentNode;
|
|
228
|
+
|
|
229
|
+
const items = allItems.filter(function (el) {
|
|
230
|
+
return !isExcludedSortItem(el);
|
|
231
|
+
});
|
|
232
|
+
if (!items.length) return;
|
|
233
|
+
|
|
234
|
+
if (!_targetInitialOrders.has(target)) {
|
|
235
|
+
_targetInitialOrders.set(target, items.slice());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let ordered;
|
|
239
|
+
if (direction === 'none') {
|
|
240
|
+
const original = _targetInitialOrders.get(target) || items;
|
|
241
|
+
_targetInitialOrders.delete(target);
|
|
242
|
+
ordered = original.filter(function (el) {
|
|
243
|
+
return el.parentNode === parent && !isExcludedSortItem(el);
|
|
244
|
+
});
|
|
245
|
+
} else {
|
|
246
|
+
const field = this.field;
|
|
247
|
+
const column = this.column;
|
|
248
|
+
const values = items.map(function (el) { return _readItemValue(el, field, column); });
|
|
249
|
+
const type = detectValueType(values);
|
|
250
|
+
const collator = typeof Intl !== 'undefined'
|
|
251
|
+
? new Intl.Collator(getLocale(this.dom), { sensitivity: 'base', numeric: true })
|
|
252
|
+
: null;
|
|
253
|
+
|
|
254
|
+
const comparator = createSortComparator(direction, type, collator, function (el) {
|
|
255
|
+
return _readItemValue(el, field, column);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
ordered = items.slice().sort(comparator);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const frag = document.createDocumentFragment();
|
|
262
|
+
let orderIdx = 0;
|
|
263
|
+
for (let i = 0; i < allItems.length; i++) {
|
|
264
|
+
const el = allItems[i];
|
|
265
|
+
if (isExcludedSortItem(el)) {
|
|
266
|
+
frag.appendChild(el);
|
|
267
|
+
} else if (orderIdx < ordered.length) {
|
|
268
|
+
frag.appendChild(ordered[orderIdx++]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
parent.appendChild(frag);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// ─── Destroy ───────────────────────────────────────────────
|
|
275
|
+
|
|
276
|
+
_component.prototype.destroy = function () {
|
|
277
|
+
if (this._destroyed) return;
|
|
278
|
+
this._destroyed = true;
|
|
279
|
+
this.dom.removeEventListener('click', this._onClick);
|
|
280
|
+
document.removeEventListener('ln-sort:change', this._onSortChange);
|
|
281
|
+
if (this.hashEnabled && this._onHashChange) {
|
|
282
|
+
window.removeEventListener('hashchange', this._onHashChange);
|
|
283
|
+
}
|
|
284
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// ─── Attribute Sync ────────────────────────────────────────
|
|
288
|
+
|
|
289
|
+
function _syncAttribute(el, attrName) {
|
|
290
|
+
const instance = el[DOM_ATTRIBUTE];
|
|
291
|
+
if (!instance || instance._destroyed) return;
|
|
292
|
+
if (attrName === FIELD_ATTR) {
|
|
293
|
+
const th = el.closest('th');
|
|
294
|
+
instance.column = (!instance.field && th) ? th.cellIndex : null;
|
|
295
|
+
} else if (attrName === STATE_ATTR) {
|
|
296
|
+
const nextState = normalizeSortDirection(el.getAttribute(STATE_ATTR));
|
|
297
|
+
if (nextState !== instance._state) {
|
|
298
|
+
instance._apply(nextState);
|
|
299
|
+
}
|
|
300
|
+
} else if (attrName === HASH_ATTR) {
|
|
301
|
+
if (instance.hashEnabled && instance._onHashChange) {
|
|
302
|
+
window.removeEventListener('hashchange', instance._onHashChange);
|
|
303
|
+
}
|
|
304
|
+
instance.nsKey = resolveHashNamespace(el, 'sort');
|
|
305
|
+
instance.hashEnabled = !!instance.nsKey;
|
|
306
|
+
if (instance.hashEnabled) {
|
|
307
|
+
window.addEventListener('hashchange', instance._onHashChange);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ─── Registration ──────────────────────────────────────────
|
|
313
|
+
|
|
314
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-sort', {
|
|
315
|
+
attributes: ATTRIBUTES,
|
|
316
|
+
persist: {
|
|
317
|
+
attr: STATE_ATTR,
|
|
318
|
+
hashActive: function (el) { return !!resolveHashNamespace(el, 'sort'); }
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
})();
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { compareValues } from '../../ln-core/compare.js';
|
|
2
|
+
|
|
3
|
+
export const SORT_DIRECTIONS = ['none', 'asc', 'desc'];
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes a sort direction string to 'asc', 'desc', or 'none'.
|
|
7
|
+
* @param {unknown} value
|
|
8
|
+
* @returns {'asc' | 'desc' | 'none'}
|
|
9
|
+
*/
|
|
10
|
+
export function normalizeSortDirection(value) {
|
|
11
|
+
const str = String(value || '').trim().toLowerCase();
|
|
12
|
+
if (str === 'asc' || str === 'ascending') return 'asc';
|
|
13
|
+
if (str === 'desc' || str === 'descending') return 'desc';
|
|
14
|
+
return 'none';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns the ARIA sort attribute value corresponding to the direction.
|
|
19
|
+
* @param {unknown} direction
|
|
20
|
+
* @returns {'ascending' | 'descending' | 'none'}
|
|
21
|
+
*/
|
|
22
|
+
export function getAriaSortValue(direction) {
|
|
23
|
+
const normalized = normalizeSortDirection(direction);
|
|
24
|
+
if (normalized === 'asc') return 'ascending';
|
|
25
|
+
if (normalized === 'desc') return 'descending';
|
|
26
|
+
return 'none';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Determines whether two sort targets represent the identical sort key.
|
|
31
|
+
* @param {{ field?: string|null, column?: number|string|null }} a
|
|
32
|
+
* @param {{ field?: string|null, column?: number|string|null }} b
|
|
33
|
+
* @returns {boolean}
|
|
34
|
+
*/
|
|
35
|
+
export function isSameSortTarget(a, b) {
|
|
36
|
+
if (!a || !b) return false;
|
|
37
|
+
if (a.field !== null && a.field !== undefined && b.field !== null && b.field !== undefined) {
|
|
38
|
+
return a.field === b.field;
|
|
39
|
+
}
|
|
40
|
+
if (a.column !== null && a.column !== undefined && b.column !== null && b.column !== undefined) {
|
|
41
|
+
return String(a.column) === String(b.column);
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates a sort comparator function for sorting an array of records/items.
|
|
48
|
+
* @param {'asc' | 'desc' | 'none'} direction
|
|
49
|
+
* @param {'number' | 'string'} valueType
|
|
50
|
+
* @param {Intl.Collator|null} [collator]
|
|
51
|
+
* @param {(item: any) => any} [getValueFn]
|
|
52
|
+
* @returns {(a: any, b: any) => number}
|
|
53
|
+
*/
|
|
54
|
+
export function createSortComparator(direction, valueType, collator, getValueFn) {
|
|
55
|
+
const normalized = normalizeSortDirection(direction);
|
|
56
|
+
if (normalized === 'none') return () => 0;
|
|
57
|
+
|
|
58
|
+
const multiplier = normalized === 'desc' ? -1 : 1;
|
|
59
|
+
const getter = typeof getValueFn === 'function' ? getValueFn : (item) => item;
|
|
60
|
+
|
|
61
|
+
return function (a, b) {
|
|
62
|
+
const valA = getter(a);
|
|
63
|
+
const valB = getter(b);
|
|
64
|
+
return compareValues(valA, valB, valueType, collator) * multiplier;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Determines whether a DOM element should be excluded from sorting (e.g. empty-state, hidden rows, templates).
|
|
70
|
+
* @param {Element|unknown} el
|
|
71
|
+
* @returns {boolean}
|
|
72
|
+
*/
|
|
73
|
+
export function isExcludedSortItem(el) {
|
|
74
|
+
if (!el || typeof el !== 'object' || el.nodeType !== 1) return true;
|
|
75
|
+
if (el.tagName === 'TEMPLATE') return true;
|
|
76
|
+
if (typeof el.hasAttribute === 'function') {
|
|
77
|
+
if (el.hasAttribute('data-ln-sort-exclude') || el.hasAttribute('hidden')) return true;
|
|
78
|
+
}
|
|
79
|
+
if (el.classList && el.classList.contains('hidden')) return true;
|
|
80
|
+
if (el.style && el.style.display === 'none') return true;
|
|
81
|
+
if (typeof el.matches === 'function') {
|
|
82
|
+
if (el.matches('.empty-state, .ln-table__empty, .ln-table__empty-state, [data-ln-empty], [data-ln-empty-state], [data-ln-table-empty]')) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Resolves the list of sortable DOM items from a target element.
|
|
91
|
+
* For tables without explicit selector, automatically targets the tbody rows.
|
|
92
|
+
* @param {Element|unknown} target
|
|
93
|
+
* @param {string|null} [itemsSelector]
|
|
94
|
+
* @returns {Element[]}
|
|
95
|
+
*/
|
|
96
|
+
export function resolveSortItems(target, itemsSelector) {
|
|
97
|
+
if (!target || typeof target !== 'object' || target.nodeType !== 1) return [];
|
|
98
|
+
const selector = itemsSelector
|
|
99
|
+
|| (typeof target.getAttribute === 'function' ? target.getAttribute('data-ln-sort-items') : null)
|
|
100
|
+
|| null;
|
|
101
|
+
if (selector && typeof target.querySelectorAll === 'function') {
|
|
102
|
+
return Array.from(target.querySelectorAll(selector));
|
|
103
|
+
}
|
|
104
|
+
if (target.tagName === 'TABLE') {
|
|
105
|
+
const tbody = target.tBodies && target.tBodies.length
|
|
106
|
+
? target.tBodies[0]
|
|
107
|
+
: (typeof target.querySelector === 'function' ? target.querySelector('tbody') : null);
|
|
108
|
+
if (tbody) {
|
|
109
|
+
return Array.from(tbody.children || []);
|
|
110
|
+
}
|
|
111
|
+
if (typeof target.querySelectorAll === 'function') {
|
|
112
|
+
return Array.from(target.querySelectorAll('tbody tr, tr'));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return Array.from(target.children || []);
|
|
116
|
+
}
|
|
117
|
+
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# ln-sortable
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
> Applied to a `<ul data-ln-sortable>` or `<ol>` list. It listens for `pointerdown`, `pointermove`, and `pointerup` events
|
|
4
|
+
> on list items (or `[data-ln-sortable-handle]`). On drag, it adds `.ln-sortable--dragging`, repositions items in the DOM via
|
|
5
|
+
> `insertBefore`, and places a placeholder element. On release, it removes drag classes, purges the placeholder, and emits an `ln-sortable:change` CustomEvent.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ It focuses strictly on visual DOM restructuring, delegating server-side synchron
|
|
|
10
10
|
|
|
11
11
|
1. **Pointer Concurrency:** Built natively on Pointer Events APIs (`pointerdown`, `pointermove`, `pointerup`). It replaces heavy HTML5 Drag & Drop frameworks, offering high-performance dragging and layout shifts across desktop, mobile, and hybrid touch displays.
|
|
12
12
|
2. **Visual Isolation:** The primitive does not import or inject inline styles or layout rules. Instead, it exposes CSS state hooks (e.g. `.ln-sortable--dragging`) on active elements, leaving transitions and placeholders fully to the stylesheet.
|
|
13
|
-
3. **HTML Attribute as Single Source of Truth:** Component states are governed entirely by the `data-ln-sortable` attribute.
|
|
13
|
+
3. **HTML Attribute as Single Source of Truth:** Component states are governed entirely by the `data-ln-sortable` attribute. Writing the attribute is the only way to enable or disable the component; the write is observed via `MutationObserver` to coordinate internals.
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -87,11 +87,7 @@ Fired when an item drop successfully changes the DOM index order.
|
|
|
87
87
|
- **Payload (`detail`)**: `{ item: HTMLElement, oldIndex: number, newIndex: number }`
|
|
88
88
|
|
|
89
89
|
### `ln-sortable:enabled` / `ln-sortable:disabled`
|
|
90
|
-
Fired when `data-ln-sortable` toggles between enabled and `"disabled"`
|
|
91
|
-
- **Payload (`detail`)**: `{ target: HTMLElement }`
|
|
92
|
-
|
|
93
|
-
### `ln-sortable:destroyed`
|
|
94
|
-
Fired inside `destroy()`, after the `pointerdown` listener is removed.
|
|
90
|
+
Fired when `data-ln-sortable` toggles between enabled and `"disabled"` — written directly on the host and picked up by the shared `MutationObserver`.
|
|
95
91
|
- **Payload (`detail`)**: `{ target: HTMLElement }`
|
|
96
92
|
|
|
97
93
|
---
|
|
@@ -110,7 +106,7 @@ Fired inside `destroy()`, after the `pointerdown` listener is removed.
|
|
|
110
106
|
|
|
111
107
|
## 🔧 Internals
|
|
112
108
|
|
|
113
|
-
Source: `
|
|
109
|
+
Source: `components/ln-sortable/ln-sortable.js`. Each `[data-ln-sortable]` container gets a `_component` instance at `element.lnSortable` (`dom`, `isEnabled`, `_dragging` — the child currently being dragged, or `null` — and the bound `pointerdown` handler).
|
|
114
110
|
|
|
115
111
|
### Handle resolution
|
|
116
112
|
|
|
@@ -126,7 +122,7 @@ On `pointerdown`: if the target (or an ancestor) carries `data-ln-sortable-handl
|
|
|
126
122
|
|
|
127
123
|
### Attribute-driven enable/disable
|
|
128
124
|
|
|
129
|
-
`data-ln-sortable` (absent value) = enabled, `data-ln-sortable="disabled"` = disabled.
|
|
125
|
+
`data-ln-sortable` (absent value) = enabled, `data-ln-sortable="disabled"` = disabled. The shared `MutationObserver` picks up the attribute write, updates `isEnabled` inline, and dispatches `ln-sortable:enabled`/`ln-sortable:disabled`. No cancelable before-event — the state change is immediate.
|
|
130
126
|
|
|
131
127
|
### MutationObserver
|
|
132
128
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@use '../../theme/config/mixins' as *;
|
|
2
|
+
|
|
3
|
+
[data-ln-debug] {
|
|
4
|
+
// 1. Host Container Check: data-ln-sortable belongs on list or grid containers
|
|
5
|
+
[data-ln-sortable]:not(ul, ol, div, tbody) {
|
|
6
|
+
@include dev-inline-error("data-ln-sortable belongs on <ul>, <ol>, <tbody>, or <div> containers");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// 2. Handle Nesting Check: sortable handles must be inside a sortable container
|
|
10
|
+
[data-ln-sortable-handle]:not([data-ln-sortable] *) {
|
|
11
|
+
@include dev-inline-error("[data-ln-sortable-handle] is orphaned (not inside a [data-ln-sortable] container)");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";function O(){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 y(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 i=null;for(let s=1;s<t.length;s++)if(t[s]&&t[s].nodeType===1){i=t[s];break}if(!y(i))return}e.apply(console,t)}}function C(e,t,n){const i=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:i}))}function j(e,t,n){const i=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i);const s=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:i});return e.dispatchEvent(s),s}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 D={};function N(e,t){D[e]=t}function P(e){return D[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=N,window.lnCore.getDataMapper=P);function V(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,m(function(){new MutationObserver(function(){C(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const T={};function H(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];T[n]=t}function U(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return T[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=H,window.lnCore.getLocaleFallback=U,window.lnCore.ensureLocaleObserver=V);const A={};function Q(e,t){A[e]||(A[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=A[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function $(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let o=0;o<n.length;o++){const l=n[o],r=l.getAttribute("data-ln-field");t[r]!=null&&(l.textContent=t[r])}const i=e.querySelectorAll("[data-ln-attr]");for(let o=0;o<i.length;o++){const l=i[o],r=l.getAttribute("data-ln-attr").split(",");for(let a=0;a<r.length;a++){const c=r[a].trim().split(":");if(c.length!==2)continue;const u=c[0].trim(),f=c[1].trim();t[f]!=null&&l.setAttribute(u,t[f])}}const s=e.querySelectorAll("[data-ln-show]");for(let o=0;o<s.length;o++){const l=s[o],r=l.getAttribute("data-ln-show");r in t&&l.classList.toggle("hidden",!t[r])}const d=e.querySelectorAll("[data-ln-class]");for(let o=0;o<d.length;o++){const l=d[o],r=l.getAttribute("data-ln-class").split(",");for(let a=0;a<r.length;a++){const c=r[a].trim().split(":");if(c.length!==2)continue;const u=c[0].trim(),f=c[1].trim();f in t&&l.classList.toggle(u,!!t[f])}}return e}function K(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 i=0;i<n.length;i++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[i],t??null),n[i].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)$(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 I(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const d=n.currentNode;d.textContent.indexOf("{{")!==-1&&(d.textContent=d.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(o,l){return t[l]!==void 0?t[l]:""}))}const i=function(d,o){return t[o]!==void 0?t[o]:""},s=Array.from(e.querySelectorAll("*"));e.nodeType===1&&s.push(e);for(let d=0;d<s.length;d++){const o=s[d],l=o.attributes;for(let r=0;r<l.length;r++){const a=l[r];a.value.indexOf("{{")!==-1&&o.setAttribute(a.name,a.value.replace(/\{\{\s*(\w+)\s*\}\}/g,i))}}return e}function Y(e,t,n,i,s,d){const o={};for(let r=0;r<e.children.length;r++){const a=e.children[r],c=a.getAttribute("data-ln-render-key");c&&(o[c]=a)}const l=document.createDocumentFragment();for(let r=0;r<t.length;r++){const a=t[r],c=String(i(a));let u=o[c];if(u)s(u,a,r);else{const f=Q(n,d);if(!f||(I(f,a),u=f.firstElementChild,!u))continue;u.setAttribute("data-ln-render-key",c),s(u,a,r)}l.appendChild(u)}e.textContent="",e.appendChild(l)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=I,window.lnCore.fill=$,window.lnCore.lnFill=K,window.lnCore.renderList=Y);function R(e,t,n,i,s){if(!e||t===null)return!0;const d=i||"ln-component",o=e.type;if(o==="trigger"||o==="marker"||o==="string"||o==="list"||!o||t===""&&e.fallback!==void 0)return!0;const l=r=>{s?console.warn(r,s):console.warn(r)};if(o==="boolean"){const r=t.trim().toLowerCase();return r!==""&&r!=="true"&&r!=="false"&&r!=="1"&&r!=="0"?(l(`[${d}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(o==="enum"){const r=e.values||[];return r.includes(t)?!0:(l(`[${d}] Invalid value "${t}" for attribute "${n}". Allowed: ${r.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(o==="integer"){if(!/^-?\d+$/.test(t))return l(`[${d}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const r=parseInt(t,10);return e.min!==void 0&&r<e.min?(l(`[${d}] Value ${r} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&r>e.max?(l(`[${d}] Value ${r} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(o==="float")return isNaN(Number(t))?(l(`[${d}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(o==="json")try{return JSON.parse(t),!0}catch(r){return l(`[${d}] Invalid JSON for attribute "${n}": ${r.message}. Fallback: ${e.fallback}.`),!1}return!0}function G(e){const t={};for(const n in e){const i=e[n];i&&i.effect&&(t[n]=i.effect)}return Object.keys(t).length?t:null}function J(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 v(e,t,n,i){if(e.nodeType!==1)return;const d=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",o=Array.from(e.querySelectorAll(d));e.matches&&e.matches(d)&&o.push(e);for(const l of o)if(!l[n]){window.lnCore._persistSink&&l.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(l,t);try{l[n]=new i(l)}catch(r){console.error("["+n+"] init failed",l,r)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function X(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function z(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 q(){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 Z(e){const t=q(),n=e.observed||[];for(let i=0;i<n.length;i++){const s=n[i];t.byAttr.has(s)||t.byAttr.set(s,[]),t.byAttr.get(s).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const i in e.attributes){t.byDeclaredAttr.has(i)||t.byDeclaredAttr.set(i,[]);const s=t.byDeclaredAttr.get(i);s.some(d=>d.componentTag===e.componentTag)||s.push({spec:e.attributes[i],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const i=J(e);if(i===null)t.reactiveWildcard.push(e);else for(const s of i)t.byReactive.has(s)||t.byReactive.set(s,[]),t.byReactive.get(s).push(e)}e.persist&&t.persist.push(e)}function M(e,t,n,i){for(let s=0;s<e.length;s++){const d=e[s];if(!t[d.attribute])continue;const o=d.effects&&d.effects[n];o?o(t,n,i):d.onAttrChange&&(!d.declared||d.declared.has(n))&&d.onAttrChange(t,n,i)}}function ee(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const i=q(),s=i.byAttr.get(n);if(O()&&i.byDeclaredAttr&&i.byDeclaredAttr.has(n)&&y(t)){const d=i.byDeclaredAttr.get(n),o=t.getAttribute(n);for(let l=0;l<d.length;l++)R(d[l].spec,o,n,d[l].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||s)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const d=i.byReactive.get(n);d&&M(d,t,n,e.oldValue),i.reactiveWildcard.length&&M(i.reactiveWildcard,t,n,e.oldValue)}if(s)for(let d=0;d<s.length;d++){const o=s[d];if(o.handler){o.handler(t,n,e.oldValue);continue}o.onAttributeChange&&t[o.attribute]?o.onAttributeChange(t,n):(v(t,o.selector,o.attribute,o.ComponentFn),o.onInit&&o.onInit(t))}}function te(){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{ee(t[n])}catch(i){console.error("[ln-core] mutation handler failed",t[n].target,i)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function B(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function ne(e){const t=B();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const i=t[n];if(i.onSubtreeChange){const s=i.query,d=e.target.nodeType===1?e.target.matches(s)?e.target:e.target.closest(s):e.target.parentElement?e.target.parentElement.closest(s):null;d&&i.onSubtreeChange(d,e)}}for(let n=0;n<e.addedNodes.length;n++){const i=e.addedNodes[n];if(i.nodeType===1)for(let s=0;s<t.length;s++){const d=t[s];v(i,d.selector,d.attribute,d.ComponentFn),d.onInit&&d.onInit(i)}}for(let n=0;n<e.removedNodes.length;n++){const i=e.removedNodes[n];if(i.nodeType===1)for(let s=0;s<t.length;s++){const d=t[s],o=d.query,l=Array.from(i.querySelectorAll(o));i.matches&&i.matches(o)&&l.push(i);for(let r=0;r<l.length;r++){const a=l[r];if(!document.contains(a)){const c=a[d.attribute];if(c&&typeof c.destroy=="function")try{c.destroy()}catch(u){console.error("["+d.attribute+"] destroy failed",a,u)}delete a[d.attribute]}}}}}}function re(){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 i=t[n];if(i.type==="childList")try{ne(i)}catch(s){console.error("[ln-core] lifecycle handler failed",i.target,s)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function oe(e,t,n,i,s={}){const d=s.extraAttributes||[],o=s.onAttributeChange||null,l=s.onSubtreeChange||null,r=s.onInit||null,a=s.onAttrChange||null,c=s.effects||null,u=s.attributes||null,f=u?G(u):c,h=u?new Set(Object.keys(u)):null,g=s.persist||null;function b(k){const w=k||document.body;if(v(w,e,t,n),u&&O())for(const p in u){const be=u[p],S=Array.from(w.querySelectorAll("["+p+"]"));w.matches&&w.matches("["+p+"]")&&S.push(w);for(let L=0;L<S.length;L++){const x=S[L];y(x)&&R(be,x.getAttribute(p),p,i,x)}}r&&r(w)}const E=[];if(e.indexOf("[")!==-1){const k=/\[([\w-]+)/g;let w;for(;(w=k.exec(e))!==null;)E.push(w[1])}else E.push(e);Z({selector:e,attribute:t,componentTag:i,attributes:u,ComponentFn:n,onInit:r,observed:E.concat(d),onAttributeChange:o,onAttrChange:a,effects:f,declared:h,persist:g}),te();const we=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";B().push({selector:e,attribute:t,ComponentFn:n,onInit:r,onSubtreeChange:l,query:we}),re(),window[t]=b;function W(){X()>0?z(function(){b(document.body)}):b(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",W):W(),b}function F(e){return(e||"").replace(/^#/,"")}function _(e){const t=e===void 0?location.hash:e,n={},i=F(t);if(!i)return n;const s=i.split("&");for(let d=0;d<s.length;d++){const o=s[d];if(!o)continue;const l=o.indexOf(":"),r=l>-1?o.slice(0,l):o,a=l>-1?o.slice(l+1):"";if(r)try{n[r]=decodeURIComponent(a)}catch{n[r]=a}}return n}function ie(e){if(!e)return null;const t=_();return e in t?t[e]:null}function le(e,t){if(!e)return;const n=_();t==null?delete n[e]:n[e]=String(t);const s=Object.keys(n).map(function(d){const o=n[d];return o===""?d:d+":"+encodeURIComponent(o)}).join("&");F(location.hash)!==s&&(location.hash=s)}function se(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function de(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 i=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return i?t?i+"-"+t:i:t||null}function ae(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function ce(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ue(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function fe(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),i=e.slice(t+1),s=i?i.split(",").map(function(d){try{return decodeURIComponent(d)}catch{return d}}).filter(Boolean):[];return{key:n,values:s}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=_,window.lnCore.hashGet=ie,window.lnCore.hashSet=le,window.lnCore.hashLinkClick=se,window.lnCore.resolveHashNamespace=de,window.lnCore.hashSortEncode=ae,window.lnCore.hashSortDecode=ce,window.lnCore.hashFilterEncode=ue,window.lnCore.hashFilterDecode=fe),(function(){const e="data-ln-sortable",t="lnSortable",n="data-ln-sortable-handle";if(window[t]!==void 0)return;const i={"data-ln-sortable":{effect:d,type:"enum",values:["enabled","disabled"],fallback:"enabled",description:"Enables drag-and-drop item reordering or disables when set to disabled"},"data-ln-sortable-handle":{type:"marker",description:"Designates an element as the drag handle for its parent sortable item"}};function s(o){this.dom=o,this.isEnabled=o.getAttribute(e)!=="disabled",this._dragging=null,o.setAttribute("aria-roledescription","sortable list");const l=this;return this._onPointerDown=function(r){l.isEnabled&&l._handlePointerDown(r)},o.addEventListener("pointerdown",this._onPointerDown),this}s.prototype.destroy=function(){this.dom[t]&&(this.dom.removeEventListener("pointerdown",this._onPointerDown),delete this.dom[t])},s.prototype._handlePointerDown=function(o){let l=o.target.closest("["+n+"]"),r;if(l){for(r=l;r&&r.parentElement!==this.dom;)r=r.parentElement;if(!r||r.parentElement!==this.dom)return}else{if(this.dom.querySelector("["+n+"]"))return;for(r=o.target;r&&r.parentElement!==this.dom;)r=r.parentElement;if(!r||r.parentElement!==this.dom)return;l=r}const c=Array.from(this.dom.children).indexOf(r);if(j(this.dom,"ln-sortable:before-drag",{item:r,index:c}).defaultPrevented)return;o.preventDefault(),l.setPointerCapture(o.pointerId),this._dragging=r,r.classList.add("ln-sortable--dragging"),r.setAttribute("aria-grabbed","true"),this.dom.classList.add("ln-sortable--active"),C(this.dom,"ln-sortable:drag-start",{item:r,index:c});const f=this,h=function(b){f._handlePointerMove(b)},g=function(b){f._handlePointerEnd(b),l.removeEventListener("pointermove",h),l.removeEventListener("pointerup",g),l.removeEventListener("pointercancel",g)};l.addEventListener("pointermove",h),l.addEventListener("pointerup",g),l.addEventListener("pointercancel",g)},s.prototype._handlePointerMove=function(o){if(!this._dragging)return;const l=Array.from(this.dom.children),r=this._dragging;for(const a of l)a.classList.remove("ln-sortable--drop-before","ln-sortable--drop-after");for(const a of l){if(a===r)continue;const c=a.getBoundingClientRect(),u=c.top+c.height/2;if(o.clientY>=c.top&&o.clientY<u){a.classList.add("ln-sortable--drop-before");break}else if(o.clientY>=u&&o.clientY<=c.bottom){a.classList.add("ln-sortable--drop-after");break}}},s.prototype._handlePointerEnd=function(o){if(!this._dragging)return;const l=this._dragging,r=Array.from(this.dom.children),a=r.indexOf(l);let c=null,u=null;for(const f of r){if(f.classList.contains("ln-sortable--drop-before")){c=f,u="before";break}if(f.classList.contains("ln-sortable--drop-after")){c=f,u="after";break}}for(const f of r)f.classList.remove("ln-sortable--drop-before","ln-sortable--drop-after");if(l.classList.remove("ln-sortable--dragging"),l.removeAttribute("aria-grabbed"),this.dom.classList.remove("ln-sortable--active"),c&&c!==l){u==="before"?this.dom.insertBefore(l,c):this.dom.insertBefore(l,c.nextElementSibling);const h=Array.from(this.dom.children).indexOf(l);C(this.dom,"ln-sortable:reordered",{item:l,oldIndex:a,newIndex:h})}this._dragging=null};function d(o){const l=o[t];if(!l)return;const r=o.getAttribute(e)!=="disabled";r!==l.isEnabled&&(l.isEnabled=r,C(o,r?"ln-sortable:enabled":"ln-sortable:disabled",{target:o}))}oe(e,t,s,"ln-sortable",{attributes:i})})()})();
|
|
@@ -0,0 +1,36 @@
|
|
|
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-sortable",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {
|
|
6
|
+
"data-ln-debug": {
|
|
7
|
+
"direction": null,
|
|
8
|
+
"sources": [
|
|
9
|
+
"ln-sortable-dev.scss"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"data-ln-sortable": {
|
|
13
|
+
"direction": "author",
|
|
14
|
+
"sources": [
|
|
15
|
+
"ln-sortable-dev.scss",
|
|
16
|
+
"src/ln-sortable.js"
|
|
17
|
+
],
|
|
18
|
+
"type": "enum",
|
|
19
|
+
"values": [
|
|
20
|
+
"enabled",
|
|
21
|
+
"disabled"
|
|
22
|
+
],
|
|
23
|
+
"fallback": "enabled",
|
|
24
|
+
"description": "Enables drag-and-drop item reordering or disables when set to disabled"
|
|
25
|
+
},
|
|
26
|
+
"data-ln-sortable-handle": {
|
|
27
|
+
"direction": "author",
|
|
28
|
+
"sources": [
|
|
29
|
+
"ln-sortable-dev.scss",
|
|
30
|
+
"src/ln-sortable.js"
|
|
31
|
+
],
|
|
32
|
+
"type": "marker",
|
|
33
|
+
"description": "Designates an element as the drag handle for its parent sortable item"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -9,6 +9,12 @@ import { registerComponent, dispatch, dispatchCancelable } from '../../ln-core';
|
|
|
9
9
|
|
|
10
10
|
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
11
11
|
|
|
12
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
13
|
+
const ATTRIBUTES = {
|
|
14
|
+
'data-ln-sortable': { effect: _syncEnabled, type: 'enum', values: ['enabled', 'disabled'], fallback: 'enabled', description: 'Enables drag-and-drop item reordering or disables when set to disabled' },
|
|
15
|
+
'data-ln-sortable-handle': { type: 'marker', description: 'Designates an element as the drag handle for its parent sortable item' }
|
|
16
|
+
};
|
|
17
|
+
|
|
12
18
|
// ─── Component ─────────────────────────────────────────────
|
|
13
19
|
|
|
14
20
|
function _component(dom) {
|
|
@@ -29,22 +35,11 @@ import { registerComponent, dispatch, dispatchCancelable } from '../../ln-core';
|
|
|
29
35
|
return this;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
// ───
|
|
33
|
-
|
|
34
|
-
_component.prototype.enable = function () {
|
|
35
|
-
if (this.isEnabled) return;
|
|
36
|
-
this.dom.setAttribute(DOM_SELECTOR, '');
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
_component.prototype.disable = function () {
|
|
40
|
-
if (!this.isEnabled) return;
|
|
41
|
-
this.dom.setAttribute(DOM_SELECTOR, 'disabled');
|
|
42
|
-
};
|
|
38
|
+
// ─── Lifecycle ─────────────────────────────────────────────
|
|
43
39
|
|
|
44
40
|
_component.prototype.destroy = function () {
|
|
45
41
|
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
46
42
|
this.dom.removeEventListener('pointerdown', this._onPointerDown);
|
|
47
|
-
dispatch(this.dom, 'ln-sortable:destroyed', { target: this.dom });
|
|
48
43
|
delete this.dom[DOM_ATTRIBUTE];
|
|
49
44
|
};
|
|
50
45
|
|
|
@@ -198,6 +193,6 @@ import { registerComponent, dispatch, dispatchCancelable } from '../../ln-core';
|
|
|
198
193
|
// ─── Init ──────────────────────────────────────────────────
|
|
199
194
|
|
|
200
195
|
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-sortable', {
|
|
201
|
-
|
|
196
|
+
attributes: ATTRIBUTES
|
|
202
197
|
});
|
|
203
198
|
})();
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# ln-stat
|
|
2
2
|
|
|
3
|
+
> Applied to an inline or block element (`<strong data-ln-stat="storeName" data-ln-stat-filter="active:true">`). On initialization, it bubbles an `ln-stat:request-count` CustomEvent to `ln-data-coordinator` and listens for `ln-stat:set-count`, updating its `textContent` with the resolved number and removing the `.is-loading` class. It stores zero count state internally, relying entirely on the coordinator to re-deliver counts on store mutations.
|
|
4
|
+
|
|
3
5
|
Displays a live count from an `ln-data-store` via the `ln-data-coordinator` binder. Updates automatically on every store mutation. Opt-in: add `data-ln-stat="<storeName>"` to any inline element.
|
|
4
6
|
|
|
5
7
|
---
|
|
@@ -52,4 +54,4 @@ The `is-loading` class is removed on first delivery — add it to show a loading
|
|
|
52
54
|
|
|
53
55
|
## 🔧 Internals
|
|
54
56
|
|
|
55
|
-
Source: `
|
|
57
|
+
Source: `components/ln-stat/ln-stat.js`. The coordinator's `_serveStat` method handles `ln-stat:request-count`: reads `data-ln-stat` from the dispatching element, guards with `_ownsStore(name)`, calls `store.count(filters)` (`filters` from `e.detail.filters`), and dispatches `ln-stat:set-count { count }` back on the element. On every store mutation, the coordinator's `_refreshAll()` re-parses `data-ln-stat-filter` from each stat element and re-calls `store.count()` — the component itself holds no count state between deliveries.
|