meno-core 1.0.52 → 1.0.54
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/.claude/settings.local.json +1 -3
- package/bin/cli.ts +48 -57
- package/build-astro.ts +296 -108
- package/build-next.ts +1374 -0
- package/build-static.test.ts +39 -10
- package/build-static.ts +127 -127
- package/dist/bin/cli.js +34 -38
- package/dist/bin/cli.js.map +2 -2
- package/dist/build-static.js +12 -11
- package/dist/chunks/chunk-2AR55GYH.js +42 -0
- package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
- package/dist/chunks/{chunk-CXCBV2M7.js → chunk-2FN4UOVO.js} +581 -502
- package/dist/chunks/chunk-2FN4UOVO.js.map +7 -0
- package/dist/chunks/chunk-3XER4E5W.js +168 -0
- package/dist/chunks/chunk-3XER4E5W.js.map +7 -0
- package/dist/chunks/chunk-5ETZFREW.js +514 -0
- package/dist/chunks/chunk-5ETZFREW.js.map +7 -0
- package/dist/chunks/{chunk-2MHDV5BF.js → chunk-7E4IF5L7.js} +15 -21
- package/dist/chunks/chunk-7E4IF5L7.js.map +7 -0
- package/dist/chunks/{chunk-7NIC4I3V.js → chunk-7HWQUVTU.js} +1691 -1316
- package/dist/chunks/chunk-7HWQUVTU.js.map +7 -0
- package/dist/chunks/{chunk-EDQSMAMP.js → chunk-AE3QK5QW.js} +189 -19
- package/dist/chunks/chunk-AE3QK5QW.js.map +7 -0
- package/dist/chunks/{chunk-HNLUO36W.js → chunk-F6KTJYGV.js} +8 -8
- package/dist/chunks/chunk-F6KTJYGV.js.map +7 -0
- package/dist/chunks/{chunk-WQFG7PAH.js → chunk-FZITJSSS.js} +2 -6
- package/dist/chunks/chunk-FZITJSSS.js.map +7 -0
- package/dist/chunks/{chunk-H4JSCDNW.js → chunk-GSYYA5GX.js} +25 -2
- package/dist/chunks/chunk-GSYYA5GX.js.map +7 -0
- package/dist/chunks/{chunk-2QK6U5UK.js → chunk-HIZMY3EP.js} +12 -2
- package/dist/chunks/chunk-HIZMY3EP.js.map +7 -0
- package/dist/chunks/{chunk-AZQYF6KE.js → chunk-I2WEGYA7.js} +41 -176
- package/dist/chunks/chunk-I2WEGYA7.js.map +7 -0
- package/dist/chunks/{chunk-I7YIGZXT.js → chunk-JNO3CNLJ.js} +6 -9
- package/dist/chunks/chunk-JNO3CNLJ.js.map +7 -0
- package/dist/chunks/{chunk-UB44F4Z2.js → chunk-NVRBTSQG.js} +2 -4
- package/dist/chunks/chunk-NVRBTSQG.js.map +7 -0
- package/dist/chunks/{chunk-LHLHPYSP.js → chunk-Q4OBWKXG.js} +48 -40
- package/dist/chunks/chunk-Q4OBWKXG.js.map +7 -0
- package/dist/chunks/{chunk-A725KYFK.js → chunk-QTE32Y53.js} +780 -323
- package/dist/chunks/chunk-QTE32Y53.js.map +7 -0
- package/dist/chunks/{chunk-LPVETICS.js → chunk-STDY3OVM.js} +397 -84
- package/dist/chunks/chunk-STDY3OVM.js.map +7 -0
- package/dist/chunks/configService-PRJZF7Y6.js +14 -0
- package/dist/chunks/{constants-GWBAD66U.js → constants-KIQEYMAM.js} +2 -2
- package/dist/chunks/{fs-JGINUXGL.js → fs-ZI5JEU7V.js} +2 -2
- package/dist/entries/server-router.js +14 -19
- package/dist/entries/server-router.js.map +2 -2
- package/dist/lib/client/index.js +957 -356
- package/dist/lib/client/index.js.map +4 -4
- package/dist/lib/server/index.js +1538 -328
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +277 -73
- package/dist/lib/shared/index.js.map +4 -4
- package/dist/lib/shared/richtext/index.js +1 -1
- package/dist/lib/test-utils/index.js +38 -60
- package/dist/lib/test-utils/index.js.map +2 -2
- package/entries/client-router.tsx +14 -172
- package/entries/server-router.tsx +1 -7
- package/lib/client/ClientInitializer.ts +8 -8
- package/lib/client/ErrorBoundary.test.tsx +156 -151
- package/lib/client/ErrorBoundary.tsx +184 -121
- package/lib/client/componentRegistry.test.ts +96 -108
- package/lib/client/componentRegistry.ts +1 -2
- package/lib/client/contexts/ThemeContext.tsx +3 -2
- package/lib/client/core/ComponentBuilder.test.ts +513 -560
- package/lib/client/core/ComponentBuilder.ts +335 -146
- package/lib/client/core/ComponentRenderer.test.tsx +1 -2
- package/lib/client/core/ComponentRenderer.tsx +46 -33
- package/lib/client/core/builders/embedBuilder.ts +246 -54
- package/lib/client/core/builders/linkBuilder.ts +71 -44
- package/lib/client/core/builders/linkNodeBuilder.ts +78 -53
- package/lib/client/core/builders/listBuilder.ts +137 -89
- package/lib/client/core/builders/localeListBuilder.ts +95 -60
- package/lib/client/core/builders/types.ts +5 -5
- package/lib/client/core/cmsTemplateProcessor.ts +7 -7
- package/lib/client/elementRegistry.ts +3 -3
- package/lib/client/fontFamiliesService.test.ts +68 -0
- package/lib/client/fontFamiliesService.ts +69 -0
- package/lib/client/hmr/HMRManager.tsx +8 -0
- package/lib/client/hmrCssReload.ts +166 -0
- package/lib/client/hmrWebSocket.ts +9 -14
- package/lib/client/hooks/useColorVariables.test.ts +21 -21
- package/lib/client/hooks/useColorVariables.ts +14 -10
- package/lib/client/hooks/usePropertyAutocomplete.ts +3 -5
- package/lib/client/hooks/useVariables.ts +4 -4
- package/lib/client/hydration/HydrationUtils.test.ts +24 -25
- package/lib/client/hydration/HydrationUtils.ts +3 -4
- package/lib/client/i18nConfigService.test.ts +2 -7
- package/lib/client/i18nConfigService.ts +2 -2
- package/lib/client/index.ts +4 -0
- package/lib/client/meno-filter/MenoFilter.test.ts +19 -21
- package/lib/client/meno-filter/MenoFilter.ts +5 -9
- package/lib/client/meno-filter/bindings.ts +15 -40
- package/lib/client/meno-filter/init.ts +1 -1
- package/lib/client/meno-filter/renderer.ts +23 -29
- package/lib/client/meno-filter/script.generated.ts +1 -3
- package/lib/client/meno-filter/ui.ts +5 -5
- package/lib/client/meno-filter/updates.ts +15 -21
- package/lib/client/navigation.test.ts +159 -159
- package/lib/client/navigation.ts +0 -1
- package/lib/client/responsiveStyleResolver.test.ts +230 -228
- package/lib/client/responsiveStyleResolver.ts +13 -16
- package/lib/client/routing/RouteLoader.test.ts +25 -26
- package/lib/client/routing/RouteLoader.ts +30 -37
- package/lib/client/routing/Router.tsx +112 -18
- package/lib/client/scripts/ScriptExecutor.test.ts +270 -128
- package/lib/client/scripts/ScriptExecutor.ts +69 -33
- package/lib/client/services/PrefetchService.test.ts +2 -2
- package/lib/client/services/PrefetchService.ts +10 -24
- package/lib/client/styleProcessor.test.ts +9 -9
- package/lib/client/styleProcessor.ts +18 -15
- package/lib/client/styles/StyleInjector.test.ts +122 -115
- package/lib/client/styles/StyleInjector.ts +25 -7
- package/lib/client/styles/UtilityClassCollector.ts +26 -27
- package/lib/client/styles/cspNonce.test.ts +64 -0
- package/lib/client/styles/cspNonce.ts +63 -0
- package/lib/client/templateEngine.test.ts +600 -448
- package/lib/client/templateEngine.ts +205 -64
- package/lib/client/theme.ts +0 -1
- package/lib/client/utils/toast.ts +0 -1
- package/lib/server/__integration__/api-routes.test.ts +8 -4
- package/lib/server/__integration__/cms-integration.test.ts +1 -4
- package/lib/server/__integration__/server-lifecycle.test.ts +2 -5
- package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
- package/lib/server/__integration__/static-assets.test.ts +1 -1
- package/lib/server/__integration__/test-helpers.ts +84 -70
- package/lib/server/ab/generateFunctions.ts +12 -10
- package/lib/server/astro/cmsPageEmitter.ts +47 -32
- package/lib/server/astro/componentEmitter.ts +82 -37
- package/lib/server/astro/cssCollector.ts +10 -26
- package/lib/server/astro/nodeToAstro.test.ts +1750 -30
- package/lib/server/astro/nodeToAstro.ts +327 -178
- package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +260 -0
- package/lib/server/astro/normalizeOrphanTemplateProps.ts +176 -0
- package/lib/server/astro/pageEmitter.ts +9 -13
- package/lib/server/astro/tailwindMapper.test.ts +10 -37
- package/lib/server/astro/tailwindMapper.ts +33 -40
- package/lib/server/astro/templateTransformer.ts +14 -17
- package/lib/server/createServer.ts +16 -17
- package/lib/server/cssGenerator.test.ts +35 -44
- package/lib/server/cssGenerator.ts +6 -17
- package/lib/server/draftPageStore.ts +49 -0
- package/lib/server/fileWatcher.test.ts +124 -10
- package/lib/server/fileWatcher.ts +164 -98
- package/lib/server/index.ts +20 -2
- package/lib/server/jsonLoader.test.ts +39 -2
- package/lib/server/jsonLoader.ts +33 -31
- package/lib/server/middleware/cors.test.ts +20 -20
- package/lib/server/middleware/cors.ts +28 -4
- package/lib/server/middleware/errorHandler.test.ts +5 -3
- package/lib/server/middleware/errorHandler.ts +3 -8
- package/lib/server/middleware/index.ts +0 -1
- package/lib/server/middleware/logger.test.ts +7 -5
- package/lib/server/middleware/logger.ts +10 -22
- package/lib/server/pageCache.test.ts +76 -77
- package/lib/server/pageCache.ts +0 -1
- package/lib/server/projectContext.ts +4 -3
- package/lib/server/providers/fileSystemCMSProvider.test.ts +124 -95
- package/lib/server/providers/fileSystemCMSProvider.ts +35 -20
- package/lib/server/providers/fileSystemPageProvider.test.ts +84 -0
- package/lib/server/providers/fileSystemPageProvider.ts +39 -12
- package/lib/server/routes/api/cms.test.ts +26 -14
- package/lib/server/routes/api/cms.ts +9 -14
- package/lib/server/routes/api/components.ts +35 -34
- package/lib/server/routes/api/config.ts +0 -1
- package/lib/server/routes/api/core-routes.ts +49 -76
- package/lib/server/routes/api/functions.ts +8 -16
- package/lib/server/routes/api/index.ts +3 -6
- package/lib/server/routes/api/pages.ts +21 -32
- package/lib/server/routes/api/shared.test.ts +1 -1
- package/lib/server/routes/api/shared.ts +65 -6
- package/lib/server/routes/api/variables.test.ts +1 -3
- package/lib/server/routes/api/variables.ts +1 -1
- package/lib/server/routes/index.ts +106 -19
- package/lib/server/routes/pages.ts +47 -35
- package/lib/server/routes/static.ts +16 -4
- package/lib/server/runtime/bundler.ts +47 -32
- package/lib/server/runtime/fs.ts +3 -13
- package/lib/server/runtime/httpServer.ts +5 -9
- package/lib/server/services/ColorService.ts +32 -27
- package/lib/server/services/EnumService.test.ts +2 -6
- package/lib/server/services/EnumService.ts +7 -2
- package/lib/server/services/VariableService.test.ts +1 -5
- package/lib/server/services/VariableService.ts +6 -1
- package/lib/server/services/cmsService.test.ts +116 -78
- package/lib/server/services/cmsService.ts +24 -54
- package/lib/server/services/componentService.test.ts +303 -20
- package/lib/server/services/componentService.ts +397 -76
- package/lib/server/services/configService.test.ts +9 -31
- package/lib/server/services/configService.ts +20 -27
- package/lib/server/services/fileWatcherService.ts +44 -30
- package/lib/server/services/index.ts +0 -1
- package/lib/server/services/pageService.test.ts +24 -3
- package/lib/server/services/pageService.ts +135 -16
- package/lib/server/ssr/attributeBuilder.ts +24 -8
- package/lib/server/ssr/buildErrorOverlay.ts +12 -13
- package/lib/server/ssr/clientDataInjector.ts +7 -21
- package/lib/server/ssr/cmsSSRProcessor.ts +3 -6
- package/lib/server/ssr/cssCollector.ts +1 -1
- package/lib/server/ssr/errorOverlay.test.ts +21 -2
- package/lib/server/ssr/errorOverlay.ts +39 -18
- package/lib/server/ssr/htmlGenerator.nonce.test.ts +3 -9
- package/lib/server/ssr/htmlGenerator.test.ts +173 -56
- package/lib/server/ssr/htmlGenerator.ts +191 -112
- package/lib/server/ssr/imageMetadata.test.ts +3 -1
- package/lib/server/ssr/imageMetadata.ts +25 -19
- package/lib/server/ssr/jsCollector.test.ts +3 -13
- package/lib/server/ssr/jsCollector.ts +3 -8
- package/lib/server/ssr/liveReloadIntegration.test.ts +184 -22
- package/lib/server/ssr/metaTagGenerator.ts +2 -2
- package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
- package/lib/server/ssr/ssrRenderer.test.ts +263 -246
- package/lib/server/ssr/ssrRenderer.ts +700 -231
- package/lib/server/ssrRenderer.test.ts +1044 -950
- package/lib/server/utils/jsonLineMapper.test.ts +28 -28
- package/lib/server/utils/jsonLineMapper.ts +1 -1
- package/lib/server/validateStyleCoverage.ts +18 -20
- package/lib/server/webflow/buildWebflow.ts +41 -53
- package/lib/server/webflow/nodeToWebflow.test.ts +150 -218
- package/lib/server/webflow/nodeToWebflow.ts +195 -258
- package/lib/server/webflow/styleMapper.test.ts +15 -56
- package/lib/server/webflow/styleMapper.ts +33 -41
- package/lib/server/webflow/types.ts +1 -8
- package/lib/server/websocketManager.ts +16 -20
- package/lib/shared/attributeNodeUtils.test.ts +15 -15
- package/lib/shared/attributeNodeUtils.ts +5 -12
- package/lib/shared/breakpoints.ts +4 -11
- package/lib/shared/cmsQueryParser.test.ts +50 -42
- package/lib/shared/cmsQueryParser.ts +49 -31
- package/lib/shared/colorVariableUtils.test.ts +5 -5
- package/lib/shared/colorVariableUtils.ts +3 -8
- package/lib/shared/componentRefs.ts +41 -0
- package/lib/shared/constants.test.ts +3 -3
- package/lib/shared/constants.ts +12 -8
- package/lib/shared/cssGeneration.test.ts +262 -144
- package/lib/shared/cssGeneration.ts +189 -514
- package/lib/shared/cssNamedColors.ts +152 -30
- package/lib/shared/cssProperties.test.ts +5 -6
- package/lib/shared/cssProperties.ts +479 -111
- package/lib/shared/elementClassName.test.ts +109 -109
- package/lib/shared/elementClassName.ts +1 -1
- package/lib/shared/elementUtils.ts +12 -16
- package/lib/shared/errorLogger.ts +2 -10
- package/lib/shared/errors.test.ts +2 -13
- package/lib/shared/errors.ts +2 -8
- package/lib/shared/expressionEvaluator.test.ts +119 -0
- package/lib/shared/expressionEvaluator.ts +95 -22
- package/lib/shared/fontCss.ts +101 -0
- package/lib/shared/fontLoader.test.ts +19 -5
- package/lib/shared/fontLoader.ts +8 -86
- package/lib/shared/friendlyError.test.ts +87 -0
- package/lib/shared/friendlyError.ts +120 -0
- package/lib/shared/gradientUtils.test.ts +1 -5
- package/lib/shared/gradientUtils.ts +2 -6
- package/lib/shared/hrefRefs.test.ts +130 -0
- package/lib/shared/hrefRefs.ts +92 -0
- package/lib/shared/i18n.test.ts +1 -1
- package/lib/shared/i18n.ts +13 -34
- package/lib/shared/index.ts +56 -0
- package/lib/shared/inlineSvgStyleRules.test.ts +108 -0
- package/lib/shared/inlineSvgStyleRules.ts +132 -0
- package/lib/shared/interactiveStyleMappings.test.ts +11 -33
- package/lib/shared/interactiveStyleMappings.ts +9 -16
- package/lib/shared/interactiveStyles.test.ts +165 -188
- package/lib/shared/interfaces/contentProvider.ts +14 -1
- package/lib/shared/itemTemplateUtils.test.ts +20 -12
- package/lib/shared/itemTemplateUtils.ts +23 -36
- package/lib/shared/jsonRepair.ts +8 -2
- package/lib/shared/libraryLoader.test.ts +15 -49
- package/lib/shared/libraryLoader.ts +7 -22
- package/lib/shared/netlifyLocale404.test.ts +179 -0
- package/lib/shared/netlifyLocale404.ts +110 -0
- package/lib/shared/nodeUtils.test.ts +24 -16
- package/lib/shared/nodeUtils.ts +49 -19
- package/lib/shared/pathArrayUtils.test.ts +1 -2
- package/lib/shared/pathArrayUtils.ts +1 -1
- package/lib/shared/pathSecurity.ts +1 -1
- package/lib/shared/pathUtils.test.ts +4 -6
- package/lib/shared/pathUtils.ts +42 -48
- package/lib/shared/paths/Path.test.ts +2 -2
- package/lib/shared/paths/Path.ts +0 -1
- package/lib/shared/paths/PathConverter.test.ts +1 -1
- package/lib/shared/paths/PathConverter.ts +14 -17
- package/lib/shared/paths/PathUtils.ts +9 -10
- package/lib/shared/paths/PathValidator.test.ts +2 -15
- package/lib/shared/paths/PathValidator.ts +11 -9
- package/lib/shared/paths/index.ts +1 -2
- package/lib/shared/propResolver.test.ts +240 -244
- package/lib/shared/propResolver.ts +14 -25
- package/lib/shared/pxToRem.test.ts +7 -6
- package/lib/shared/pxToRem.ts +2 -5
- package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +9 -5
- package/lib/shared/registry/ClientRegistry.ts +0 -1
- package/lib/shared/registry/ComponentRegistry.test.ts +43 -29
- package/lib/shared/registry/ComponentRegistry.ts +9 -11
- package/lib/shared/registry/NodeTypeDefinition.ts +15 -8
- package/lib/shared/registry/RegistryManager.ts +1 -2
- package/lib/shared/registry/SSRRegistry.ts +0 -1
- package/lib/shared/registry/createNodeType.ts +7 -9
- package/lib/shared/registry/defineNodeType.ts +2 -6
- package/lib/shared/registry/index.ts +0 -1
- package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
- package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
- package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +47 -18
- package/lib/shared/registry/nodeTypes/LinkNodeType.ts +22 -20
- package/lib/shared/registry/nodeTypes/ListNodeType.ts +78 -74
- package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
- package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +6 -7
- package/lib/shared/registry/nodeTypes/index.ts +10 -2
- package/lib/shared/responsiveScaling.test.ts +15 -31
- package/lib/shared/responsiveScaling.ts +55 -37
- package/lib/shared/responsiveStyleUtils.ts +11 -13
- package/lib/shared/richtext/htmlToTiptap.test.ts +23 -14
- package/lib/shared/richtext/htmlToTiptap.ts +1 -3
- package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
- package/lib/shared/richtext/types.ts +1 -8
- package/lib/shared/slugTranslator.test.ts +37 -13
- package/lib/shared/slugTranslator.ts +31 -11
- package/lib/shared/slugify.ts +9 -15
- package/lib/shared/styleNodeUtils.test.ts +8 -8
- package/lib/shared/styleNodeUtils.ts +9 -11
- package/lib/shared/styleUtils.test.ts +87 -61
- package/lib/shared/styleUtils.ts +5 -6
- package/lib/shared/themeDefaults.test.ts +11 -11
- package/lib/shared/themeDefaults.ts +3 -4
- package/lib/shared/tree/PathBuilder.test.ts +160 -109
- package/lib/shared/tree/PathBuilder.ts +121 -59
- package/lib/shared/treePathUtils.test.ts +2 -10
- package/lib/shared/treePathUtils.ts +54 -59
- package/lib/shared/types/api.ts +1 -2
- package/lib/shared/types/cms.ts +25 -21
- package/lib/shared/types/comment.ts +132 -0
- package/lib/shared/types/components.ts +27 -25
- package/lib/shared/types/errors.test.ts +1 -6
- package/lib/shared/types/errors.ts +3 -7
- package/lib/shared/types/experiments.ts +28 -28
- package/lib/shared/types/index.ts +14 -2
- package/lib/shared/types/rendering.ts +8 -0
- package/lib/shared/types/styles.ts +0 -1
- package/lib/shared/types/variables.test.ts +4 -13
- package/lib/shared/types/variables.ts +48 -27
- package/lib/shared/types.ts +1 -2
- package/lib/shared/utilityClassConfig.ts +648 -319
- package/lib/shared/utilityClassMapper.test.ts +213 -78
- package/lib/shared/utilityClassMapper.ts +188 -246
- package/lib/shared/utilityClassNames.ts +326 -0
- package/lib/shared/utils.test.ts +2 -10
- package/lib/shared/utils.ts +19 -10
- package/lib/shared/validation/cmsValidators.ts +2 -1
- package/lib/shared/validation/commentValidators.test.ts +53 -0
- package/lib/shared/validation/commentValidators.ts +80 -0
- package/lib/shared/validation/index.ts +1 -0
- package/lib/shared/validation/propValidator.test.ts +18 -20
- package/lib/shared/validation/propValidator.ts +12 -17
- package/lib/shared/validation/schemas.test.ts +24 -33
- package/lib/shared/validation/schemas.ts +469 -344
- package/lib/shared/validation/validators.test.ts +1 -6
- package/lib/shared/validation/validators.ts +89 -68
- package/lib/shared/viewportUnits.integration.test.ts +46 -0
- package/lib/shared/viewportUnits.test.ts +91 -0
- package/lib/shared/viewportUnits.ts +63 -0
- package/lib/test-utils/dom-setup.ts +7 -1
- package/lib/test-utils/factories/ConsoleMockFactory.ts +3 -7
- package/lib/test-utils/factories/DomMockFactory.ts +7 -19
- package/lib/test-utils/factories/EventMockFactory.ts +7 -13
- package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
- package/lib/test-utils/factories/ServerMockFactory.ts +5 -9
- package/lib/test-utils/factories/StoreMockFactory.ts +14 -25
- package/lib/test-utils/fixtures.ts +45 -45
- package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
- package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
- package/lib/test-utils/helpers.ts +1 -5
- package/lib/test-utils/index.ts +0 -4
- package/lib/test-utils/mockFactories.ts +12 -18
- package/lib/test-utils/mocks.ts +4 -2
- package/package.json +1 -1
- package/scripts/build-meno-filter.ts +1 -4
- package/vite.config.ts +4 -4
- package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
- package/dist/chunks/chunk-2QK6U5UK.js.map +0 -7
- package/dist/chunks/chunk-7NIC4I3V.js.map +0 -7
- package/dist/chunks/chunk-A725KYFK.js.map +0 -7
- package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
- package/dist/chunks/chunk-CXCBV2M7.js.map +0 -7
- package/dist/chunks/chunk-EDQSMAMP.js.map +0 -7
- package/dist/chunks/chunk-H4JSCDNW.js.map +0 -7
- package/dist/chunks/chunk-HNLUO36W.js.map +0 -7
- package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
- package/dist/chunks/chunk-J23ZX5AP.js +0 -241
- package/dist/chunks/chunk-J23ZX5AP.js.map +0 -7
- package/dist/chunks/chunk-LHLHPYSP.js.map +0 -7
- package/dist/chunks/chunk-LPVETICS.js.map +0 -7
- package/dist/chunks/chunk-UB44F4Z2.js.map +0 -7
- package/dist/chunks/chunk-WQFG7PAH.js.map +0 -7
- package/dist/chunks/configService-R3OGU2UD.js +0 -13
- /package/dist/chunks/{configService-R3OGU2UD.js.map → configService-PRJZF7Y6.js.map} +0 -0
- /package/dist/chunks/{constants-GWBAD66U.js.map → constants-KIQEYMAM.js.map} +0 -0
- /package/dist/chunks/{fs-JGINUXGL.js.map → fs-ZI5JEU7V.js.map} +0 -0
|
@@ -83,7 +83,7 @@ describe('MenoFilter', () => {
|
|
|
83
83
|
Promise.resolve({
|
|
84
84
|
ok: true,
|
|
85
85
|
json: () => Promise.resolve(sampleItems),
|
|
86
|
-
})
|
|
86
|
+
}),
|
|
87
87
|
);
|
|
88
88
|
const originalFetch = (globalThis as any).fetch;
|
|
89
89
|
(globalThis as any).fetch = mockFetch;
|
|
@@ -127,7 +127,7 @@ describe('MenoFilter', () => {
|
|
|
127
127
|
Promise.resolve({
|
|
128
128
|
ok: false,
|
|
129
129
|
status: 404,
|
|
130
|
-
})
|
|
130
|
+
}),
|
|
131
131
|
);
|
|
132
132
|
const originalFetch = (globalThis as any).fetch;
|
|
133
133
|
(globalThis as any).fetch = mockFetch;
|
|
@@ -157,7 +157,7 @@ describe('MenoFilter', () => {
|
|
|
157
157
|
Promise.resolve({
|
|
158
158
|
ok: true,
|
|
159
159
|
json: () => Promise.resolve([{ _id: 'fetch', title: 'Fetch Data' }]),
|
|
160
|
-
})
|
|
160
|
+
}),
|
|
161
161
|
);
|
|
162
162
|
const originalFetch = (globalThis as any).fetch;
|
|
163
163
|
(globalThis as any).fetch = mockFetch;
|
|
@@ -193,7 +193,7 @@ describe('MenoFilter', () => {
|
|
|
193
193
|
const result = filter.filter({ category: 'tech' });
|
|
194
194
|
|
|
195
195
|
expect(result).toHaveLength(3);
|
|
196
|
-
expect(result.every(item => item.category === 'tech')).toBe(true);
|
|
196
|
+
expect(result.every((item) => item.category === 'tech')).toBe(true);
|
|
197
197
|
});
|
|
198
198
|
|
|
199
199
|
test('should filter by multiple criteria (AND logic)', () => {
|
|
@@ -217,7 +217,7 @@ describe('MenoFilter', () => {
|
|
|
217
217
|
|
|
218
218
|
test('should emit to subscribers on filter', () => {
|
|
219
219
|
let emittedItems: CMSItemClient[] = [];
|
|
220
|
-
filter.subscribe(items => {
|
|
220
|
+
filter.subscribe((items) => {
|
|
221
221
|
emittedItems = items;
|
|
222
222
|
});
|
|
223
223
|
|
|
@@ -245,8 +245,8 @@ describe('MenoFilter', () => {
|
|
|
245
245
|
const result = filter.search('world');
|
|
246
246
|
|
|
247
247
|
expect(result).toHaveLength(2);
|
|
248
|
-
expect(result.map(i => i.title)).toContain('Hello World');
|
|
249
|
-
expect(result.map(i => i.title)).toContain('Goodbye World');
|
|
248
|
+
expect(result.map((i) => i.title)).toContain('Hello World');
|
|
249
|
+
expect(result.map((i) => i.title)).toContain('Goodbye World');
|
|
250
250
|
});
|
|
251
251
|
|
|
252
252
|
test('should search specified fields only', () => {
|
|
@@ -337,9 +337,7 @@ describe('MenoFilter', () => {
|
|
|
337
337
|
});
|
|
338
338
|
|
|
339
339
|
test('should find item by _filename', () => {
|
|
340
|
-
const itemsWithFilename = [
|
|
341
|
-
{ _id: '1', _filename: 'hello-world', title: 'Hello' },
|
|
342
|
-
];
|
|
340
|
+
const itemsWithFilename = [{ _id: '1', _filename: 'hello-world', title: 'Hello' }];
|
|
343
341
|
const mockElement = {
|
|
344
342
|
textContent: JSON.stringify(itemsWithFilename),
|
|
345
343
|
};
|
|
@@ -424,7 +422,7 @@ describe('MenoFilter', () => {
|
|
|
424
422
|
await filter.init();
|
|
425
423
|
|
|
426
424
|
let receivedItems: CMSItemClient[] = [];
|
|
427
|
-
filter.subscribe(items => {
|
|
425
|
+
filter.subscribe((items) => {
|
|
428
426
|
receivedItems = items;
|
|
429
427
|
});
|
|
430
428
|
|
|
@@ -648,7 +646,7 @@ describe('MenoFilter', () => {
|
|
|
648
646
|
await filter.init();
|
|
649
647
|
|
|
650
648
|
let receivedItems: CMSItemClient[] = [];
|
|
651
|
-
filter.subscribe(items => {
|
|
649
|
+
filter.subscribe((items) => {
|
|
652
650
|
receivedItems = items;
|
|
653
651
|
});
|
|
654
652
|
|
|
@@ -701,7 +699,7 @@ describe('MenoFilter', () => {
|
|
|
701
699
|
const result = filter.filter({ price: { $gt: 100 } });
|
|
702
700
|
|
|
703
701
|
expect(result).toHaveLength(2);
|
|
704
|
-
expect(result.map(i => i.price)).toEqual([200, 150]);
|
|
702
|
+
expect(result.map((i) => i.price)).toEqual([200, 150]);
|
|
705
703
|
});
|
|
706
704
|
|
|
707
705
|
test('should filter numbers from string criteria', async () => {
|
|
@@ -718,7 +716,7 @@ describe('MenoFilter', () => {
|
|
|
718
716
|
const result = filter.filter({ price: { $gte: '100', $lte: '150' } });
|
|
719
717
|
|
|
720
718
|
expect(result).toHaveLength(2);
|
|
721
|
-
expect(result.map(i => i.price)).toEqual([100, 150]);
|
|
719
|
+
expect(result.map((i) => i.price)).toEqual([100, 150]);
|
|
722
720
|
});
|
|
723
721
|
|
|
724
722
|
test('should filter dates with type coercion', async () => {
|
|
@@ -735,7 +733,7 @@ describe('MenoFilter', () => {
|
|
|
735
733
|
const result = filter.filter({ date: { $gt: '2024-01-31' } });
|
|
736
734
|
|
|
737
735
|
expect(result).toHaveLength(2);
|
|
738
|
-
expect(result.map(i => i.date)).toEqual(['2024-02-15', '2024-03-15']);
|
|
736
|
+
expect(result.map((i) => i.date)).toEqual(['2024-02-15', '2024-03-15']);
|
|
739
737
|
});
|
|
740
738
|
|
|
741
739
|
test('should filter booleans with type coercion', async () => {
|
|
@@ -752,7 +750,7 @@ describe('MenoFilter', () => {
|
|
|
752
750
|
const result = filter.filter({ featured: 'true' });
|
|
753
751
|
|
|
754
752
|
expect(result).toHaveLength(2);
|
|
755
|
-
expect(result.every(i => i.featured === true)).toBe(true);
|
|
753
|
+
expect(result.every((i) => i.featured === true)).toBe(true);
|
|
756
754
|
});
|
|
757
755
|
|
|
758
756
|
test('setFieldType() should update field types', async () => {
|
|
@@ -773,7 +771,7 @@ describe('MenoFilter', () => {
|
|
|
773
771
|
result = filter.filter({ price: { $gt: 100 } });
|
|
774
772
|
|
|
775
773
|
expect(result).toHaveLength(2);
|
|
776
|
-
expect(result.map(i => i.price)).toEqual([200, 150]);
|
|
774
|
+
expect(result.map((i) => i.price)).toEqual([200, 150]);
|
|
777
775
|
});
|
|
778
776
|
|
|
779
777
|
test('setFieldTypes() should set multiple types', async () => {
|
|
@@ -820,7 +818,7 @@ describe('MenoFilter', () => {
|
|
|
820
818
|
const result = filter.filterRange('price', { min: 100, max: 200 });
|
|
821
819
|
|
|
822
820
|
expect(result).toHaveLength(3);
|
|
823
|
-
expect(result.map(i => i.price).sort((a, b) => (a as number) - (b as number))).toEqual([100, 150, 200]);
|
|
821
|
+
expect(result.map((i) => i.price).sort((a, b) => (a as number) - (b as number))).toEqual([100, 150, 200]);
|
|
824
822
|
});
|
|
825
823
|
|
|
826
824
|
test('should filter with only min', async () => {
|
|
@@ -836,7 +834,7 @@ describe('MenoFilter', () => {
|
|
|
836
834
|
const result = filter.filterRange('price', { min: 150 });
|
|
837
835
|
|
|
838
836
|
expect(result).toHaveLength(3);
|
|
839
|
-
expect(result.every(i => (i.price as number) >= 150)).toBe(true);
|
|
837
|
+
expect(result.every((i) => (i.price as number) >= 150)).toBe(true);
|
|
840
838
|
});
|
|
841
839
|
|
|
842
840
|
test('should filter with only max', async () => {
|
|
@@ -852,7 +850,7 @@ describe('MenoFilter', () => {
|
|
|
852
850
|
const result = filter.filterRange('price', { max: 100 });
|
|
853
851
|
|
|
854
852
|
expect(result).toHaveLength(2);
|
|
855
|
-
expect(result.every(i => (i.price as number) <= 100)).toBe(true);
|
|
853
|
+
expect(result.every((i) => (i.price as number) <= 100)).toBe(true);
|
|
856
854
|
});
|
|
857
855
|
|
|
858
856
|
test('should clear filter when both min and max are empty', async () => {
|
|
@@ -956,7 +954,7 @@ describe('MenoFilter', () => {
|
|
|
956
954
|
const result = filter.search('recat', ['title']);
|
|
957
955
|
|
|
958
956
|
expect(result.length).toBeGreaterThanOrEqual(1);
|
|
959
|
-
expect(result.some(i => i.title === 'React')).toBe(true);
|
|
957
|
+
expect(result.some((i) => i.title === 'React')).toBe(true);
|
|
960
958
|
});
|
|
961
959
|
|
|
962
960
|
test('should use exact match for short queries (< 3 chars)', async () => {
|
|
@@ -797,9 +797,7 @@ export class MenoFilter {
|
|
|
797
797
|
}
|
|
798
798
|
|
|
799
799
|
const queryString = params.toString();
|
|
800
|
-
const url = queryString
|
|
801
|
-
? `${window.location.pathname}?${queryString}`
|
|
802
|
-
: window.location.pathname;
|
|
800
|
+
const url = queryString ? `${window.location.pathname}?${queryString}` : window.location.pathname;
|
|
803
801
|
|
|
804
802
|
if (this.urlMode === 'push') {
|
|
805
803
|
history.pushState(null, '', url);
|
|
@@ -1082,17 +1080,14 @@ export class MenoFilter {
|
|
|
1082
1080
|
|
|
1083
1081
|
// Apply OR criteria
|
|
1084
1082
|
if (this.orCriteria.length > 0) {
|
|
1085
|
-
result = result.filter((item) =>
|
|
1086
|
-
this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria))
|
|
1087
|
-
);
|
|
1083
|
+
result = result.filter((item) => this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria)));
|
|
1088
1084
|
}
|
|
1089
1085
|
|
|
1090
1086
|
// Apply search
|
|
1091
1087
|
if (this.searchQuery) {
|
|
1092
1088
|
const query = this.searchQuery;
|
|
1093
1089
|
result = result.filter((item) => {
|
|
1094
|
-
const fieldsToSearch =
|
|
1095
|
-
this.searchFields.length > 0 ? this.searchFields : Object.keys(item);
|
|
1090
|
+
const fieldsToSearch = this.searchFields.length > 0 ? this.searchFields : Object.keys(item);
|
|
1096
1091
|
return fieldsToSearch.some((field) => {
|
|
1097
1092
|
const value = item[field];
|
|
1098
1093
|
if (typeof value !== 'string') return false;
|
|
@@ -1259,13 +1254,14 @@ export class MenoFilter {
|
|
|
1259
1254
|
case '$nin':
|
|
1260
1255
|
return Array.isArray(opValue) ? !opValue.includes(itemValue) : true;
|
|
1261
1256
|
|
|
1262
|
-
case '$empty':
|
|
1257
|
+
case '$empty': {
|
|
1263
1258
|
const isEmpty =
|
|
1264
1259
|
itemValue === undefined ||
|
|
1265
1260
|
itemValue === null ||
|
|
1266
1261
|
itemValue === '' ||
|
|
1267
1262
|
(Array.isArray(itemValue) && itemValue.length === 0);
|
|
1268
1263
|
return opValue ? isEmpty : !isEmpty;
|
|
1264
|
+
}
|
|
1269
1265
|
|
|
1270
1266
|
default:
|
|
1271
1267
|
console.warn(`MenoFilter: Unknown operator "${op}"`);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* to MenoFilter instances via data attributes.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { MenoFilter } from './MenoFilter';
|
|
8
|
+
import type { MenoFilter } from './MenoFilter';
|
|
9
9
|
import { ATTR } from './constants';
|
|
10
10
|
import type { FilterInstance, FilterMode } from './types';
|
|
11
11
|
|
|
@@ -42,12 +42,7 @@ function getFilterMode(element: HTMLElement): FilterMode | null {
|
|
|
42
42
|
* Handle button click in multi-select mode
|
|
43
43
|
* Toggles value in $in array
|
|
44
44
|
*/
|
|
45
|
-
function handleMultiButtonClick(
|
|
46
|
-
filter: MenoFilter,
|
|
47
|
-
field: string,
|
|
48
|
-
value: string,
|
|
49
|
-
currentValue: unknown
|
|
50
|
-
): void {
|
|
45
|
+
function handleMultiButtonClick(filter: MenoFilter, field: string, value: string, currentValue: unknown): void {
|
|
51
46
|
// Get current values as array
|
|
52
47
|
let values: string[] = [];
|
|
53
48
|
if (currentValue !== undefined) {
|
|
@@ -87,9 +82,7 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
87
82
|
const { wrapper, filter, cleanup } = instance;
|
|
88
83
|
|
|
89
84
|
// Filter buttons
|
|
90
|
-
const filterButtons = wrapper.querySelectorAll<HTMLElement>(
|
|
91
|
-
`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
|
|
92
|
-
);
|
|
85
|
+
const filterButtons = wrapper.querySelectorAll<HTMLElement>(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
|
|
93
86
|
|
|
94
87
|
for (const btn of filterButtons) {
|
|
95
88
|
if (btn.tagName === 'INPUT') continue; // Handle inputs separately
|
|
@@ -118,7 +111,6 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
118
111
|
filter.addFilter(field, value);
|
|
119
112
|
}
|
|
120
113
|
}
|
|
121
|
-
|
|
122
114
|
};
|
|
123
115
|
|
|
124
116
|
btn.addEventListener('click', handler);
|
|
@@ -126,9 +118,7 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
126
118
|
}
|
|
127
119
|
|
|
128
120
|
// Filter checkboxes (allow multiple selections with OR logic)
|
|
129
|
-
const filterCheckboxes = wrapper.querySelectorAll<HTMLInputElement>(
|
|
130
|
-
`input[type="checkbox"][${ATTR.FILTER_FIELD}]`
|
|
131
|
-
);
|
|
121
|
+
const filterCheckboxes = wrapper.querySelectorAll<HTMLInputElement>(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
|
|
132
122
|
|
|
133
123
|
for (const checkbox of filterCheckboxes) {
|
|
134
124
|
const field = checkbox.getAttribute(ATTR.FILTER_FIELD)!;
|
|
@@ -139,7 +129,7 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
139
129
|
// Single mode: uncheck other checkboxes in the same field
|
|
140
130
|
if (mode === 'single' && checkbox.checked) {
|
|
141
131
|
const siblings = wrapper.querySelectorAll<HTMLInputElement>(
|
|
142
|
-
`input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]
|
|
132
|
+
`input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]`,
|
|
143
133
|
);
|
|
144
134
|
for (const sibling of siblings) {
|
|
145
135
|
if (sibling !== checkbox) {
|
|
@@ -156,9 +146,7 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
156
146
|
}
|
|
157
147
|
|
|
158
148
|
// Filter selects
|
|
159
|
-
const filterSelects = wrapper.querySelectorAll<HTMLSelectElement>(
|
|
160
|
-
`select[${ATTR.FILTER_FIELD}]`
|
|
161
|
-
);
|
|
149
|
+
const filterSelects = wrapper.querySelectorAll<HTMLSelectElement>(`select[${ATTR.FILTER_FIELD}]`);
|
|
162
150
|
|
|
163
151
|
for (const select of filterSelects) {
|
|
164
152
|
const field = select.getAttribute(ATTR.FILTER_FIELD)!;
|
|
@@ -177,9 +165,7 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
177
165
|
}
|
|
178
166
|
|
|
179
167
|
// Filter radio buttons
|
|
180
|
-
const filterRadios = wrapper.querySelectorAll<HTMLInputElement>(
|
|
181
|
-
`input[type="radio"][${ATTR.FILTER_FIELD}]`
|
|
182
|
-
);
|
|
168
|
+
const filterRadios = wrapper.querySelectorAll<HTMLInputElement>(`input[type="radio"][${ATTR.FILTER_FIELD}]`);
|
|
183
169
|
|
|
184
170
|
for (const radio of filterRadios) {
|
|
185
171
|
const field = radio.getAttribute(ATTR.FILTER_FIELD)!;
|
|
@@ -203,18 +189,12 @@ export function bindFilterControls(instance: FilterInstance): void {
|
|
|
203
189
|
/**
|
|
204
190
|
* Update filters based on checked checkboxes for a field
|
|
205
191
|
*/
|
|
206
|
-
function updateCheckboxFilters(
|
|
207
|
-
wrapper: HTMLElement,
|
|
208
|
-
filter: MenoFilter,
|
|
209
|
-
field: string
|
|
210
|
-
): void {
|
|
192
|
+
function updateCheckboxFilters(wrapper: HTMLElement, filter: MenoFilter, field: string): void {
|
|
211
193
|
const checkboxes = wrapper.querySelectorAll<HTMLInputElement>(
|
|
212
|
-
`input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]:checked
|
|
194
|
+
`input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]:checked`,
|
|
213
195
|
);
|
|
214
196
|
|
|
215
|
-
const values = Array.from(checkboxes).map(
|
|
216
|
-
(cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value
|
|
217
|
-
);
|
|
197
|
+
const values = Array.from(checkboxes).map((cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value);
|
|
218
198
|
|
|
219
199
|
if (values.length === 0) {
|
|
220
200
|
filter.removeFilter(field);
|
|
@@ -363,17 +343,13 @@ export function bindActionControls(instance: FilterInstance): void {
|
|
|
363
343
|
*/
|
|
364
344
|
export function resetFormControls(wrapper: HTMLElement): void {
|
|
365
345
|
// Reset checkboxes
|
|
366
|
-
const checkboxes = wrapper.querySelectorAll<HTMLInputElement>(
|
|
367
|
-
`input[type="checkbox"][${ATTR.FILTER_FIELD}]`
|
|
368
|
-
);
|
|
346
|
+
const checkboxes = wrapper.querySelectorAll<HTMLInputElement>(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
|
|
369
347
|
for (const cb of checkboxes) {
|
|
370
348
|
cb.checked = false;
|
|
371
349
|
}
|
|
372
350
|
|
|
373
351
|
// Reset selects
|
|
374
|
-
const selects = wrapper.querySelectorAll<HTMLSelectElement>(
|
|
375
|
-
`select[${ATTR.FILTER_FIELD}]`
|
|
376
|
-
);
|
|
352
|
+
const selects = wrapper.querySelectorAll<HTMLSelectElement>(`select[${ATTR.FILTER_FIELD}]`);
|
|
377
353
|
for (const select of selects) {
|
|
378
354
|
select.selectedIndex = 0;
|
|
379
355
|
}
|
|
@@ -421,12 +397,13 @@ export function bindPaginationControls(instance: FilterInstance): void {
|
|
|
421
397
|
case 'last':
|
|
422
398
|
filter.setPage(filter.getPageInfo().total);
|
|
423
399
|
break;
|
|
424
|
-
default:
|
|
400
|
+
default: {
|
|
425
401
|
// Numeric page
|
|
426
402
|
const page = parseInt(action || '1', 10);
|
|
427
403
|
if (!isNaN(page)) {
|
|
428
404
|
filter.setPage(page);
|
|
429
405
|
}
|
|
406
|
+
}
|
|
430
407
|
}
|
|
431
408
|
};
|
|
432
409
|
|
|
@@ -435,9 +412,7 @@ export function bindPaginationControls(instance: FilterInstance): void {
|
|
|
435
412
|
}
|
|
436
413
|
|
|
437
414
|
// Per-page select
|
|
438
|
-
const perPageSelects = wrapper.querySelectorAll<HTMLSelectElement>(
|
|
439
|
-
`[${ATTR.PER_PAGE_SELECT}]`
|
|
440
|
-
);
|
|
415
|
+
const perPageSelects = wrapper.querySelectorAll<HTMLSelectElement>(`[${ATTR.PER_PAGE_SELECT}]`);
|
|
441
416
|
|
|
442
417
|
for (const select of perPageSelects) {
|
|
443
418
|
const handler = () => {
|
|
@@ -20,7 +20,7 @@ export function renderItemFromTemplate(
|
|
|
20
20
|
item: Record<string, unknown>,
|
|
21
21
|
itemAs: string,
|
|
22
22
|
index: number,
|
|
23
|
-
total: number
|
|
23
|
+
total: number,
|
|
24
24
|
): HTMLElement {
|
|
25
25
|
let html = template;
|
|
26
26
|
|
|
@@ -69,7 +69,7 @@ export function renderNestedItemFromTemplate(
|
|
|
69
69
|
index: number,
|
|
70
70
|
total: number,
|
|
71
71
|
parentItem: Record<string, unknown>,
|
|
72
|
-
parentItemAs: string
|
|
72
|
+
parentItemAs: string,
|
|
73
73
|
): HTMLElement {
|
|
74
74
|
let html = template;
|
|
75
75
|
|
|
@@ -146,11 +146,9 @@ export function renderNestedItemFromTemplate(
|
|
|
146
146
|
export function hydrateNestedCMSLists(
|
|
147
147
|
element: HTMLElement,
|
|
148
148
|
parentItem: Record<string, unknown>,
|
|
149
|
-
parentItemAs: string
|
|
149
|
+
parentItemAs: string,
|
|
150
150
|
): void {
|
|
151
|
-
const placeholders = element.querySelectorAll<HTMLElement>(
|
|
152
|
-
'[data-cms-list-nested="true"]'
|
|
153
|
-
);
|
|
151
|
+
const placeholders = element.querySelectorAll<HTMLElement>('[data-cms-list-nested="true"]');
|
|
154
152
|
|
|
155
153
|
for (const placeholder of placeholders) {
|
|
156
154
|
hydrateNestedCMSList(placeholder, parentItem, parentItemAs);
|
|
@@ -163,7 +161,7 @@ export function hydrateNestedCMSLists(
|
|
|
163
161
|
function hydrateNestedCMSList(
|
|
164
162
|
placeholder: HTMLElement,
|
|
165
163
|
parentItem: Record<string, unknown>,
|
|
166
|
-
parentItemAs: string
|
|
164
|
+
parentItemAs: string,
|
|
167
165
|
): void {
|
|
168
166
|
const configStr = placeholder.getAttribute('data-cms-config');
|
|
169
167
|
if (!configStr) return;
|
|
@@ -176,9 +174,7 @@ function hydrateNestedCMSList(
|
|
|
176
174
|
}
|
|
177
175
|
|
|
178
176
|
const collection = config.collection;
|
|
179
|
-
const templateEl = placeholder.querySelector<HTMLTemplateElement>(
|
|
180
|
-
'template[data-nested-template]'
|
|
181
|
-
);
|
|
177
|
+
const templateEl = placeholder.querySelector<HTMLTemplateElement>('template[data-nested-template]');
|
|
182
178
|
if (!templateEl) return;
|
|
183
179
|
|
|
184
180
|
const childTemplate = templateEl.innerHTML.trim();
|
|
@@ -187,7 +183,9 @@ function hydrateNestedCMSList(
|
|
|
187
183
|
// Get collection data from inline JSON
|
|
188
184
|
const collectionData = getCollectionData(collection);
|
|
189
185
|
if (!collectionData) {
|
|
190
|
-
console.warn(
|
|
186
|
+
console.warn(
|
|
187
|
+
`MenoFilter: No data for nested collection "${collection}". Ensure clientData.enabled is true in schema.`,
|
|
188
|
+
);
|
|
191
189
|
return;
|
|
192
190
|
}
|
|
193
191
|
|
|
@@ -198,7 +196,7 @@ function hydrateNestedCMSList(
|
|
|
198
196
|
// Reference relationship: resolve IDs from parent
|
|
199
197
|
const itemIds = resolveItemsFromParent(config.items, parentItem, parentItemAs);
|
|
200
198
|
items = itemIds
|
|
201
|
-
.map(id => collectionData.find(item => item._id === id || item._filename === id))
|
|
199
|
+
.map((id) => collectionData.find((item) => item._id === id || item._filename === id))
|
|
202
200
|
.filter((item): item is Record<string, unknown> => item !== undefined);
|
|
203
201
|
} else {
|
|
204
202
|
// Filter relationship: apply filter with resolved parent values
|
|
@@ -224,15 +222,14 @@ function hydrateNestedCMSList(
|
|
|
224
222
|
i,
|
|
225
223
|
items.length,
|
|
226
224
|
parentItem,
|
|
227
|
-
parentItemAs
|
|
225
|
+
parentItemAs,
|
|
228
226
|
);
|
|
229
227
|
renderedItems.push(childElement);
|
|
230
228
|
}
|
|
231
229
|
|
|
232
230
|
// Replace placeholder content (keep template for potential re-renders)
|
|
233
|
-
const existingChildren = Array.from(placeholder.children)
|
|
234
|
-
|
|
235
|
-
existingChildren.forEach(el => el.remove());
|
|
231
|
+
const existingChildren = Array.from(placeholder.children).filter((el) => el.tagName !== 'TEMPLATE');
|
|
232
|
+
existingChildren.forEach((el) => el.remove());
|
|
236
233
|
|
|
237
234
|
for (const item of renderedItems) {
|
|
238
235
|
placeholder.appendChild(item);
|
|
@@ -260,7 +257,7 @@ function getCollectionData(collection: string): Record<string, unknown>[] | null
|
|
|
260
257
|
function resolveItemsFromParent(
|
|
261
258
|
template: string | string[],
|
|
262
259
|
parentItem: Record<string, unknown>,
|
|
263
|
-
parentItemAs: string
|
|
260
|
+
parentItemAs: string,
|
|
264
261
|
): string[] {
|
|
265
262
|
if (Array.isArray(template)) return template;
|
|
266
263
|
if (typeof template !== 'string' || !template.startsWith('{{')) return [template];
|
|
@@ -284,12 +281,12 @@ function applyNestedFilter(
|
|
|
284
281
|
items: Record<string, unknown>[],
|
|
285
282
|
filter: unknown,
|
|
286
283
|
parentItem: Record<string, unknown>,
|
|
287
|
-
parentItemAs: string
|
|
284
|
+
parentItemAs: string,
|
|
288
285
|
): Record<string, unknown>[] {
|
|
289
286
|
if (!filter) return items;
|
|
290
287
|
|
|
291
288
|
const resolved = resolveNestedFilterTemplates(filter, parentItem, parentItemAs);
|
|
292
|
-
return items.filter(item => matchesNestedFilter(item, resolved));
|
|
289
|
+
return items.filter((item) => matchesNestedFilter(item, resolved));
|
|
293
290
|
}
|
|
294
291
|
|
|
295
292
|
/**
|
|
@@ -298,12 +295,12 @@ function applyNestedFilter(
|
|
|
298
295
|
function resolveNestedFilterTemplates(
|
|
299
296
|
filter: unknown,
|
|
300
297
|
parentItem: Record<string, unknown>,
|
|
301
|
-
parentItemAs: string
|
|
298
|
+
parentItemAs: string,
|
|
302
299
|
): unknown {
|
|
303
300
|
if (Array.isArray(filter)) {
|
|
304
|
-
return filter.map(cond => ({
|
|
301
|
+
return filter.map((cond) => ({
|
|
305
302
|
...cond,
|
|
306
|
-
value: resolveNestedTemplateValue(cond.value, parentItem, parentItemAs)
|
|
303
|
+
value: resolveNestedTemplateValue(cond.value, parentItem, parentItemAs),
|
|
307
304
|
}));
|
|
308
305
|
}
|
|
309
306
|
|
|
@@ -311,7 +308,7 @@ function resolveNestedFilterTemplates(
|
|
|
311
308
|
if ('field' in filter && 'value' in filter) {
|
|
312
309
|
return {
|
|
313
310
|
...filter,
|
|
314
|
-
value: resolveNestedTemplateValue((filter as { value: unknown }).value, parentItem, parentItemAs)
|
|
311
|
+
value: resolveNestedTemplateValue((filter as { value: unknown }).value, parentItem, parentItemAs),
|
|
315
312
|
};
|
|
316
313
|
}
|
|
317
314
|
|
|
@@ -332,7 +329,7 @@ function resolveNestedFilterTemplates(
|
|
|
332
329
|
function resolveNestedTemplateValue(
|
|
333
330
|
value: unknown,
|
|
334
331
|
parentItem: Record<string, unknown>,
|
|
335
|
-
parentItemAs: string
|
|
332
|
+
parentItemAs: string,
|
|
336
333
|
): unknown {
|
|
337
334
|
if (typeof value !== 'string' || !value.startsWith('{{')) return value;
|
|
338
335
|
|
|
@@ -352,7 +349,7 @@ function matchesNestedFilter(item: Record<string, unknown>, filter: unknown): bo
|
|
|
352
349
|
if (!filter || typeof filter !== 'object') return true;
|
|
353
350
|
|
|
354
351
|
if (Array.isArray(filter)) {
|
|
355
|
-
return filter.every(cond => matchesNestedCondition(item, cond));
|
|
352
|
+
return filter.every((cond) => matchesNestedCondition(item, cond));
|
|
356
353
|
}
|
|
357
354
|
|
|
358
355
|
if ('field' in filter && 'value' in filter) {
|
|
@@ -383,10 +380,7 @@ function matchesNestedCondition(item: Record<string, unknown>, cond: { field: st
|
|
|
383
380
|
/**
|
|
384
381
|
* Apply sorting to items
|
|
385
382
|
*/
|
|
386
|
-
function applyNestedSorting(
|
|
387
|
-
items: Record<string, unknown>[],
|
|
388
|
-
sort: unknown
|
|
389
|
-
): Record<string, unknown>[] {
|
|
383
|
+
function applyNestedSorting(items: Record<string, unknown>[], sort: unknown): Record<string, unknown>[] {
|
|
390
384
|
if (!sort) return items;
|
|
391
385
|
|
|
392
386
|
const sortConfig = Array.isArray(sort) ? sort[0] : sort;
|
|
@@ -47,9 +47,7 @@ export function needsMenoFilter(html: string): boolean {
|
|
|
47
47
|
/**
|
|
48
48
|
* Check if any schemas have clientData enabled
|
|
49
49
|
*/
|
|
50
|
-
export function schemasNeedMenoFilter(
|
|
51
|
-
schemas: Array<{ clientData?: { enabled: boolean } }>
|
|
52
|
-
): boolean {
|
|
50
|
+
export function schemasNeedMenoFilter(schemas: Array<{ clientData?: { enabled: boolean } }>): boolean {
|
|
53
51
|
return schemas.some((schema) => schema.clientData?.enabled === true);
|
|
54
52
|
}
|
|
55
53
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { MenoFilter, type CMSItem } from './MenoFilter';
|
|
11
|
+
import { applyNonce } from '../styles/cspNonce';
|
|
11
12
|
|
|
12
13
|
// ============================================================================
|
|
13
14
|
// Types
|
|
@@ -56,10 +57,7 @@ const DEFAULT_OPTIONS: Required<UIOptions> = {
|
|
|
56
57
|
/**
|
|
57
58
|
* Bind UI rendering to a MenoFilter instance
|
|
58
59
|
*/
|
|
59
|
-
export function bindFilterUI(
|
|
60
|
-
collection: string,
|
|
61
|
-
options: UIOptions = {}
|
|
62
|
-
): (() => void) | null {
|
|
60
|
+
export function bindFilterUI(collection: string, options: UIOptions = {}): (() => void) | null {
|
|
63
61
|
const filter = MenoFilter.get(collection);
|
|
64
62
|
if (!filter) {
|
|
65
63
|
console.warn(`MenoFilter: No instance found for "${collection}"`);
|
|
@@ -170,7 +168,7 @@ function showElement(element: HTMLElement, options: Required<UIOptions>): void {
|
|
|
170
168
|
}, duration);
|
|
171
169
|
break;
|
|
172
170
|
|
|
173
|
-
case 'slide':
|
|
171
|
+
case 'slide': {
|
|
174
172
|
element.style.maxHeight = '0';
|
|
175
173
|
element.style.overflow = 'hidden';
|
|
176
174
|
element.classList.remove(hiddenClass);
|
|
@@ -189,6 +187,7 @@ function showElement(element: HTMLElement, options: Required<UIOptions>): void {
|
|
|
189
187
|
element.style.overflow = '';
|
|
190
188
|
}, duration);
|
|
191
189
|
break;
|
|
190
|
+
}
|
|
192
191
|
|
|
193
192
|
default:
|
|
194
193
|
element.classList.remove(hiddenClass);
|
|
@@ -304,6 +303,7 @@ function injectCSS(options: Required<UIOptions>): void {
|
|
|
304
303
|
}
|
|
305
304
|
`;
|
|
306
305
|
|
|
306
|
+
applyNonce(style);
|
|
307
307
|
document.head.appendChild(style);
|
|
308
308
|
cssInjected = true;
|
|
309
309
|
}
|
|
@@ -149,7 +149,7 @@ function filterDOMOnly(instance: FilterInstance, listEl: HTMLElement): void {
|
|
|
149
149
|
const currentPage = filter.getPageInfo().current;
|
|
150
150
|
|
|
151
151
|
// Build filtered list
|
|
152
|
-
|
|
152
|
+
const filteredItems = items.filter((item) => {
|
|
153
153
|
// Check filters
|
|
154
154
|
for (const [field, value] of Object.entries(filters)) {
|
|
155
155
|
const itemValue = getItemFieldValue(item, field);
|
|
@@ -234,7 +234,7 @@ function getItemFieldValue(item: HTMLElement, field: string): string | null {
|
|
|
234
234
|
*/
|
|
235
235
|
function getSearchableText(item: HTMLElement, fields: string[]): string {
|
|
236
236
|
if (fields.length > 0) {
|
|
237
|
-
return fields.map(f => getItemFieldValue(item, f) || '').join(' ');
|
|
237
|
+
return fields.map((f) => getItemFieldValue(item, f) || '').join(' ');
|
|
238
238
|
}
|
|
239
239
|
return item.textContent || '';
|
|
240
240
|
}
|
|
@@ -345,17 +345,11 @@ export function updateFacets(wrapper: HTMLElement, filter: MenoFilter): void {
|
|
|
345
345
|
/**
|
|
346
346
|
* Update active filters display
|
|
347
347
|
*/
|
|
348
|
-
export function updateActiveFilters(
|
|
349
|
-
wrapper: HTMLElement,
|
|
350
|
-
filter: MenoFilter,
|
|
351
|
-
instance: FilterInstance
|
|
352
|
-
): void {
|
|
348
|
+
export function updateActiveFilters(wrapper: HTMLElement, filter: MenoFilter, instance: FilterInstance): void {
|
|
353
349
|
const container = wrapper.querySelector<HTMLElement>(`[${ATTR.ACTIVE_FILTERS}]`);
|
|
354
350
|
if (!container) return;
|
|
355
351
|
|
|
356
|
-
const template = wrapper.querySelector<HTMLTemplateElement>(
|
|
357
|
-
`template[${ATTR.ACTIVE_FILTER_TEMPLATE}]`
|
|
358
|
-
);
|
|
352
|
+
const template = wrapper.querySelector<HTMLTemplateElement>(`template[${ATTR.ACTIVE_FILTER_TEMPLATE}]`);
|
|
359
353
|
|
|
360
354
|
const filters = filter.getFilters();
|
|
361
355
|
const entries = Object.entries(filters);
|
|
@@ -478,7 +472,7 @@ export function updatePagination(wrapper: HTMLElement, state: FilterState): void
|
|
|
478
472
|
export function generatePageButtons(
|
|
479
473
|
container: HTMLElement,
|
|
480
474
|
page: { current: number; total: number },
|
|
481
|
-
onClick: (page: number) => void
|
|
475
|
+
onClick: (page: number) => void,
|
|
482
476
|
): void {
|
|
483
477
|
container.innerHTML = '';
|
|
484
478
|
|
|
@@ -566,9 +560,7 @@ export function updateActiveStates(wrapper: HTMLElement, filter: MenoFilter): vo
|
|
|
566
560
|
const activeClass = wrapper.getAttribute(ATTR.ACTIVE_CLASS) || 'active';
|
|
567
561
|
|
|
568
562
|
// Update filter buttons
|
|
569
|
-
const filterButtons = wrapper.querySelectorAll<HTMLElement>(
|
|
570
|
-
`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
|
|
571
|
-
);
|
|
563
|
+
const filterButtons = wrapper.querySelectorAll<HTMLElement>(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
|
|
572
564
|
|
|
573
565
|
for (const btn of filterButtons) {
|
|
574
566
|
if (btn.tagName === 'INPUT') continue;
|
|
@@ -582,13 +574,15 @@ export function updateActiveStates(wrapper: HTMLElement, filter: MenoFilter): vo
|
|
|
582
574
|
const currentValue = filters[field];
|
|
583
575
|
|
|
584
576
|
// Only active if filter is explicitly set AND matches this value
|
|
585
|
-
const isActive =
|
|
586
|
-
currentValue
|
|
587
|
-
(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
577
|
+
const isActive =
|
|
578
|
+
currentValue !== undefined &&
|
|
579
|
+
(currentValue === value ||
|
|
580
|
+
(Array.isArray(currentValue) && currentValue.includes(value)) ||
|
|
581
|
+
(typeof currentValue === 'object' &&
|
|
582
|
+
currentValue !== null &&
|
|
583
|
+
'$in' in currentValue &&
|
|
584
|
+
Array.isArray((currentValue as { $in: unknown[] }).$in) &&
|
|
585
|
+
(currentValue as { $in: unknown[] }).$in.includes(value)));
|
|
592
586
|
|
|
593
587
|
btn.classList.toggle(activeClass, isActive);
|
|
594
588
|
}
|