@ablogcms/drawer 3.2.28-beta.0 → 3.2.29
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/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -11
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useCallback, useEffect, useRef as useRef2 } from "react";
|
|
3
3
|
import { emit } from "@ablogcms/events";
|
|
4
4
|
import useUpdateEffect from "@ablogcms/react-hooks/use-update-effect";
|
|
5
|
-
import { datasetToProps } from "@ablogcms/utils
|
|
5
|
+
import { datasetToProps } from "@ablogcms/react-utils";
|
|
6
6
|
import Drawer, { DrawerBody, DrawerFooter, DrawerHeader } from "@ablogcms/components/drawer";
|
|
7
7
|
|
|
8
8
|
// src/store/use-drawer-manager.ts
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/drawer-controller.tsx","../src/store/use-drawer-manager.ts","../src/store/drawer-manager.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { emit } from '@ablogcms/events';\nimport useUpdateEffect from '@ablogcms/react-hooks/use-update-effect';\nimport { datasetToProps } from '@ablogcms/utils/react';\nimport Drawer, { DrawerBody, DrawerFooter, DrawerHeader } from '@ablogcms/components/drawer';\nimport useDrawerManager, { UseDrawerManagerOptions } from './store/use-drawer-manager';\n\ntype DrawerProps = React.ComponentProps<typeof Drawer>;\ntype DrawerHeaderProps = React.ComponentProps<typeof DrawerHeader>;\ntype DrawerBodyProps = React.ComponentProps<typeof DrawerBody>;\ntype DrawerFooterProps = React.ComponentProps<typeof DrawerFooter>;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface DrawerControllerProps extends UseDrawerManagerOptions {}\n\n/**\n * data-drawer-*属性を動的に取得する関数\n */\nfunction parseProps<T extends 'drawer' | 'drawer-header' | 'drawer-body' | 'drawer-footer'>(\n element: HTMLElement,\n type: T\n): Partial<\n T extends 'drawer'\n ? DrawerProps\n : T extends 'drawer-header'\n ? DrawerHeaderProps\n : T extends 'drawer-body'\n ? DrawerBodyProps\n : DrawerFooterProps\n> {\n const props = datasetToProps(element.dataset, type);\n return props as Partial<\n T extends 'drawer'\n ? DrawerProps\n : T extends 'drawer-header'\n ? DrawerHeaderProps\n : T extends 'drawer-body'\n ? DrawerBodyProps\n : DrawerFooterProps\n >;\n}\n\nfunction DrawerController({ ...props }: DrawerControllerProps) {\n const { manager, state } = useDrawerManager(props);\n const openStateRef = useRef<boolean>(state.drawerProps.isOpen);\n\n const hydrateDrawerContent = useCallback(() => {\n if (manager.container) {\n ACMS.Dispatch(manager.container);\n void emit('dialog.open.after', { element: manager.container });\n ACMS.dispatchEvent('acmsDialogOpened', manager.container, {\n item: manager.container,\n });\n }\n }, [manager.container]);\n\n const handleAfterOpen = useCallback(() => {\n openStateRef.current = true;\n hydrateDrawerContent();\n }, [hydrateDrawerContent]);\n\n const handleAfterClose = useCallback(() => {\n openStateRef.current = false;\n // 閉じるトランジション完了後に state をクリアする\n manager.reset();\n }, [manager]);\n\n useEffect(() => {\n const handleOpen = (event: Event) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const element = event.target.closest<HTMLElement>(DrawerController.openTrigger);\n\n if (!element) {\n return;\n }\n\n const { target: selector, url } = element.dataset;\n\n // Drawer用 props とセレクタ情報を data-* から取得\n const drawerProps = parseProps(element, 'drawer');\n const drawerHeaderProps = parseProps(element, 'drawer-header');\n const drawerBodyProps = parseProps(element, 'drawer-body');\n const drawerFooterProps = parseProps(element, 'drawer-footer');\n\n // DrawerManagerでドロワーを開く\n manager.open({\n selector,\n url,\n drawerProps,\n drawerHeaderProps,\n drawerBodyProps,\n drawerFooterProps,\n });\n };\n\n const handleClose = (event: Event) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const element = event.target.closest<HTMLElement>(DrawerController.closeTrigger);\n\n if (!element) {\n return;\n }\n\n manager.close();\n };\n document.addEventListener('click', handleOpen);\n document.addEventListener('click', handleClose);\n\n return () => {\n document.removeEventListener('click', handleOpen);\n document.removeEventListener('click', handleClose);\n };\n }, [manager]);\n\n useUpdateEffect(() => {\n if (!openStateRef.current) {\n // ドロワーが開いた初回はonAfterOpenでhydrateするためスキップ\n return;\n }\n\n hydrateDrawerContent();\n // コンテンツが変更されたら組み込みJSを実行\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [state.content.raw]);\n\n if (!manager.container) {\n return null;\n }\n\n return (\n <Drawer\n {...state.drawerProps}\n onClose={manager.close}\n container={manager.container}\n onAfterOpen={handleAfterOpen}\n onAfterClose={handleAfterClose}\n >\n {state.content.header && (\n <DrawerHeader {...state.drawerHeaderProps}>\n {}\n <span dangerouslySetInnerHTML={{ __html: state.content.header }} />\n </DrawerHeader>\n )}\n <DrawerBody {...state.drawerBodyProps}>\n {}\n <div dangerouslySetInnerHTML={{ __html: state.content.body || state.content.raw }} />\n </DrawerBody>\n {state.content.footer && (\n <DrawerFooter {...state.drawerFooterProps}>\n {}\n <div dangerouslySetInnerHTML={{ __html: state.content.footer }} />\n </DrawerFooter>\n )}\n </Drawer>\n );\n}\n\nDrawerController.openTrigger = '.js-acms-drawer-open';\nDrawerController.closeTrigger = '.js-acms-drawer-close';\n\nexport default DrawerController;\n","import { useRef, useState, useSyncExternalStore } from 'react';\nimport DrawerManager, { DrawerManagerOptions } from './drawer-manager';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface UseDrawerManagerOptions extends Partial<DrawerManagerOptions> {}\n\nexport default function useDrawerManager(options: UseDrawerManagerOptions = {}) {\n const mostRecentOptions = useRef(options);\n\n mostRecentOptions.current = options;\n const [manager] = useState(() => new DrawerManager(mostRecentOptions));\n\n const state = useSyncExternalStore(\n manager.subscribe,\n () => manager.getSnapshot(),\n () => manager.getSnapshot()\n );\n\n ACMS.Library.drawer = manager;\n\n return {\n state,\n manager,\n };\n}\n","import { pending } from '@ablogcms/pending';\nimport type Drawer from '@ablogcms/components/drawer';\nimport type { DrawerBody, DrawerFooter, DrawerHeader } from '@ablogcms/components/drawer';\nimport { fetchContentFromUrl, getContentFromSelector, patchFormActions } from '@ablogcms/modal/content-fetcher';\nimport SecurityManager, { SecurityConfig } from '@ablogcms/modal/security-manager';\n\ntype DrawerProps = Omit<React.ComponentProps<typeof Drawer>, 'onClose'>;\ntype DrawerHeaderProps = Omit<React.ComponentProps<typeof DrawerHeader>, 'children'>;\ntype DrawerBodyProps = Omit<React.ComponentProps<typeof DrawerBody>, 'children'>;\ntype DrawerFooterProps = Omit<React.ComponentProps<typeof DrawerFooter>, 'children'>;\n\nexport interface DrawerManagerState {\n content: Content;\n drawerProps: DrawerProps;\n drawerHeaderProps: DrawerHeaderProps;\n drawerBodyProps: DrawerBodyProps;\n drawerFooterProps: DrawerFooterProps;\n}\n\nexport interface DrawerManagerOptions {\n header: string;\n body: string;\n footer: string;\n security: Partial<SecurityConfig>;\n}\n\ninterface Content {\n header?: string;\n body?: string;\n footer?: string;\n raw: string;\n}\n\ninterface DrawerManagerOpenOptions {\n selector?: string;\n url?: string;\n drawerProps?: Partial<DrawerProps>;\n drawerHeaderProps?: Partial<DrawerHeaderProps>;\n drawerBodyProps?: Partial<DrawerBodyProps>;\n drawerFooterProps?: Partial<DrawerFooterProps>;\n}\n\nconst defaultOptions: DrawerManagerOptions = {\n header: '[data-drawer-section=\"header\"]',\n body: '[data-drawer-section=\"body\"]',\n footer: '[data-drawer-section=\"footer\"]',\n security: {},\n};\n\nclass DrawerManager {\n private listeners = new Set<() => void>();\n\n private state: DrawerManagerState = {\n content: {\n raw: '',\n },\n drawerProps: {\n isOpen: false,\n },\n drawerHeaderProps: {},\n drawerBodyProps: {},\n drawerFooterProps: {},\n };\n\n #container: HTMLElement | null = null;\n\n private config: DrawerManagerOptions = defaultOptions;\n\n private securityManager: SecurityManager;\n\n constructor(options: React.MutableRefObject<Partial<DrawerManagerOptions>>) {\n this.config = { ...defaultOptions, ...options.current };\n this.securityManager = new SecurityManager(this.config.security);\n this.handleSubmit = this.handleSubmit.bind(this);\n this.open = this.open.bind(this);\n this.close = this.close.bind(this);\n this.reset = this.reset.bind(this);\n this.init();\n }\n\n subscribe = (callback: () => void) => {\n this.listeners.add(callback);\n return () => this.listeners.delete(callback);\n };\n\n getSnapshot = () => this.state;\n\n public setState(state: DrawerManagerState | ((state: DrawerManagerState) => DrawerManagerState)) {\n if (typeof state === 'function') {\n this.state = state(this.state);\n } else {\n this.state = state;\n }\n this.emit();\n }\n\n public get content() {\n return this.state.content;\n }\n\n public get drawerProps() {\n return this.state.drawerProps;\n }\n\n public get drawerHeaderProps() {\n return this.state.drawerHeaderProps;\n }\n\n public get drawerBodyProps() {\n return this.state.drawerBodyProps;\n }\n\n public get drawerFooterProps() {\n return this.state.drawerFooterProps;\n }\n\n public get container() {\n return this.#container;\n }\n\n private init() {\n // ドロワー用のコンテナ要素を作成\n const container = document.getElementById('acms-drawer-manager-container');\n if (container !== null) {\n this.#container = container;\n } else {\n this.#container = document.createElement('div');\n this.#container.id = 'acms-drawer-manager-container';\n document.body.appendChild(this.#container);\n }\n this.registerEventListeners();\n }\n\n async open(options: DrawerManagerOpenOptions = {}) {\n const removeSplash = pending.splash(ACMS.i18n('splash.default'));\n try {\n // コンテンツ取得ユーティリティを使用\n const element = await this.fetchContent(options);\n\n // コンテンツをパース\n const content = this.parseContent(element);\n\n // 状態を更新\n this.setState({\n content,\n drawerProps: {\n ...options.drawerProps,\n isOpen: true,\n },\n drawerHeaderProps: {\n ...options.drawerHeaderProps,\n },\n drawerBodyProps: {\n ...options.drawerBodyProps,\n },\n drawerFooterProps: {\n ...options.drawerFooterProps,\n },\n });\n } catch (error) {\n console.error('Failed to open drawer:', error);\n // エラーを再スローして呼び出し元でハンドリングできるようにする\n throw error;\n } finally {\n removeSplash();\n }\n }\n\n close() {\n // 閉じるトランジション中は placement などの drawerProps を保持する必要があるため、\n // isOpen のみを切り替える。完全な初期化は reset() を onAfterClose 経由で呼ぶ\n this.setState((prev) => ({\n ...prev,\n drawerProps: {\n ...prev.drawerProps,\n isOpen: false,\n },\n }));\n }\n\n reset() {\n // 閉じるトランジション完了後に呼ばれることを想定し、コンテンツと props をクリアする\n this.setState({\n content: {\n raw: '',\n },\n drawerProps: {\n isOpen: false,\n },\n drawerHeaderProps: {},\n drawerBodyProps: {},\n drawerFooterProps: {},\n });\n }\n\n private emit = () => {\n this.listeners.forEach((cb) => cb());\n };\n\n // クリーンアップ用メソッド\n destroy() {\n this.unregisterEventListeners();\n if (this.#container) {\n this.#container.remove();\n this.#container = null;\n }\n }\n\n private async handleSubmit(event: SubmitEvent) {\n if (event.defaultPrevented) {\n // バリデーターがフォームの送信をキャンセルしている場合は、何もしない\n return;\n }\n event.preventDefault();\n const form = event.target as HTMLFormElement;\n const { submitter } = event;\n const formData = new FormData(form, submitter);\n\n let isSuccess = false;\n\n const removeSplash = pending.splash(ACMS.i18n('splash.save'));\n try {\n const response = await fetch(form.action, {\n method: form.method,\n body: formData,\n headers: {\n 'X-Requested-With': 'XMLHttpRequest',\n 'X-Csrf-Token': window.csrfToken || '',\n },\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n const html = await response.text();\n isSuccess = this.checkSuccessFromContent(html);\n const content = this.parseContent(patchFormActions(html, form.action));\n this.setState((prev) => ({\n ...prev,\n content,\n }));\n } catch (error) {\n console.error('Failed to submit form:', error);\n } finally {\n removeSplash();\n if (isSuccess) {\n setTimeout(() => {\n // 成功メッセージの表示が完了してから確認ダイアログを表示\n if (confirm(ACMS.i18n('drawer.reload'))) {\n window.location.reload();\n }\n }, 500);\n }\n }\n }\n\n private checkSuccessFromContent(html: string): boolean {\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n\n // 成功メッセージのセレクタを確認\n const successSelectors = [\n '.acms-admin-alert-info', // 成功アラート\n '.acms-admin-alert-success', // 成功アラート\n '[data-status=\"success\"]', // 成功ステータス\n '.success-message', // 成功メッセージ\n ];\n\n // エラーメッセージのセレクタを確認\n const errorSelectors = [\n '.acms-admin-alert-danger', // エラーアラート\n '.acms-admin-alert-error', // エラーアラート\n '[data-status=\"error\"]', // エラーステータス\n '.error-message', // エラーメッセージ\n ];\n\n // エラーメッセージが存在する場合は失敗\n for (const selector of errorSelectors) {\n if (doc.querySelector(selector)) {\n return false;\n }\n }\n\n // 成功メッセージが存在する場合は成功\n for (const selector of successSelectors) {\n if (doc.querySelector(selector)) {\n return true;\n }\n }\n\n // デフォルトは成功とみなす(エラーがない場合)\n return true;\n }\n\n private registerEventListeners() {\n this.#container?.addEventListener('submit', this.handleSubmit);\n }\n\n private unregisterEventListeners() {\n this.#container?.removeEventListener('submit', this.handleSubmit);\n }\n\n private parseContent(htmlContent: string) {\n const { header, body, footer } = this.config;\n const result: Content = {\n raw: htmlContent,\n };\n\n if (!header && !body && !footer) {\n // セレクタが指定されていない場合は、全体をボディとして扱う\n result.body = htmlContent;\n return result;\n }\n\n // 一時的なDOM要素を作成してHTMLを解析\n const div = document.createElement('div');\n div.innerHTML = htmlContent;\n\n // ヘッダーセクションの抽出\n if (header) {\n const headerElement = div.querySelector(header);\n if (headerElement) {\n result.header = headerElement.innerHTML;\n }\n }\n\n // ボディセクションの抽出\n if (body) {\n const bodyElement = div.querySelector(body);\n if (bodyElement) {\n result.body = bodyElement.innerHTML;\n }\n }\n\n // フッターセクションの抽出\n if (footer) {\n const footerElement = div.querySelector(footer);\n if (footerElement) {\n result.footer = footerElement.innerHTML;\n }\n }\n\n // セレクタが指定されていない場合は、対応するセクションに全体のコンテンツを設定\n if (!result.header && !result.body && !result.footer) {\n result.body = htmlContent;\n }\n\n return result;\n }\n\n private fetchContent(options: DrawerManagerOpenOptions) {\n const { selector, url } = options;\n\n if (selector) {\n return getContentFromSelector(selector);\n }\n\n if (url) {\n if (!this.securityManager.validateUrl(url)) {\n throw new Error(`URL is not allowed: ${url}`);\n }\n return fetchContentFromUrl(url);\n }\n\n throw new Error('No selector or URL provided');\n }\n}\n\nexport default DrawerManager;\n"],"mappings":"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","names":["useRef","useRef"]}
|
|
1
|
+
{"version":3,"sources":["../src/drawer-controller.tsx","../src/store/use-drawer-manager.ts","../src/store/drawer-manager.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { emit } from '@ablogcms/events';\nimport useUpdateEffect from '@ablogcms/react-hooks/use-update-effect';\nimport { datasetToProps } from '@ablogcms/react-utils';\nimport Drawer, { DrawerBody, DrawerFooter, DrawerHeader } from '@ablogcms/components/drawer';\nimport useDrawerManager, { UseDrawerManagerOptions } from './store/use-drawer-manager';\n\ntype DrawerProps = React.ComponentProps<typeof Drawer>;\ntype DrawerHeaderProps = React.ComponentProps<typeof DrawerHeader>;\ntype DrawerBodyProps = React.ComponentProps<typeof DrawerBody>;\ntype DrawerFooterProps = React.ComponentProps<typeof DrawerFooter>;\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface DrawerControllerProps extends UseDrawerManagerOptions {}\n\n/**\n * data-drawer-*属性を動的に取得する関数\n */\nfunction parseProps<T extends 'drawer' | 'drawer-header' | 'drawer-body' | 'drawer-footer'>(\n element: HTMLElement,\n type: T\n): Partial<\n T extends 'drawer'\n ? DrawerProps\n : T extends 'drawer-header'\n ? DrawerHeaderProps\n : T extends 'drawer-body'\n ? DrawerBodyProps\n : DrawerFooterProps\n> {\n const props = datasetToProps(element.dataset, type);\n return props as Partial<\n T extends 'drawer'\n ? DrawerProps\n : T extends 'drawer-header'\n ? DrawerHeaderProps\n : T extends 'drawer-body'\n ? DrawerBodyProps\n : DrawerFooterProps\n >;\n}\n\nfunction DrawerController({ ...props }: DrawerControllerProps) {\n const { manager, state } = useDrawerManager(props);\n const openStateRef = useRef<boolean>(state.drawerProps.isOpen);\n\n const hydrateDrawerContent = useCallback(() => {\n if (manager.container) {\n ACMS.Dispatch(manager.container);\n void emit('dialog.open.after', { element: manager.container });\n ACMS.dispatchEvent('acmsDialogOpened', manager.container, {\n item: manager.container,\n });\n }\n }, [manager.container]);\n\n const handleAfterOpen = useCallback(() => {\n openStateRef.current = true;\n hydrateDrawerContent();\n }, [hydrateDrawerContent]);\n\n const handleAfterClose = useCallback(() => {\n openStateRef.current = false;\n // 閉じるトランジション完了後に state をクリアする\n manager.reset();\n }, [manager]);\n\n useEffect(() => {\n const handleOpen = (event: Event) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const element = event.target.closest<HTMLElement>(DrawerController.openTrigger);\n\n if (!element) {\n return;\n }\n\n const { target: selector, url } = element.dataset;\n\n // Drawer用 props とセレクタ情報を data-* から取得\n const drawerProps = parseProps(element, 'drawer');\n const drawerHeaderProps = parseProps(element, 'drawer-header');\n const drawerBodyProps = parseProps(element, 'drawer-body');\n const drawerFooterProps = parseProps(element, 'drawer-footer');\n\n // DrawerManagerでドロワーを開く\n manager.open({\n selector,\n url,\n drawerProps,\n drawerHeaderProps,\n drawerBodyProps,\n drawerFooterProps,\n });\n };\n\n const handleClose = (event: Event) => {\n if (!(event.target instanceof HTMLElement)) {\n return;\n }\n\n const element = event.target.closest<HTMLElement>(DrawerController.closeTrigger);\n\n if (!element) {\n return;\n }\n\n manager.close();\n };\n document.addEventListener('click', handleOpen);\n document.addEventListener('click', handleClose);\n\n return () => {\n document.removeEventListener('click', handleOpen);\n document.removeEventListener('click', handleClose);\n };\n }, [manager]);\n\n useUpdateEffect(() => {\n if (!openStateRef.current) {\n // ドロワーが開いた初回はonAfterOpenでhydrateするためスキップ\n return;\n }\n\n hydrateDrawerContent();\n // コンテンツが変更されたら組み込みJSを実行\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [state.content.raw]);\n\n if (!manager.container) {\n return null;\n }\n\n return (\n <Drawer\n {...state.drawerProps}\n onClose={manager.close}\n container={manager.container}\n onAfterOpen={handleAfterOpen}\n onAfterClose={handleAfterClose}\n >\n {state.content.header && (\n <DrawerHeader {...state.drawerHeaderProps}>\n {}\n <span dangerouslySetInnerHTML={{ __html: state.content.header }} />\n </DrawerHeader>\n )}\n <DrawerBody {...state.drawerBodyProps}>\n {}\n <div dangerouslySetInnerHTML={{ __html: state.content.body || state.content.raw }} />\n </DrawerBody>\n {state.content.footer && (\n <DrawerFooter {...state.drawerFooterProps}>\n {}\n <div dangerouslySetInnerHTML={{ __html: state.content.footer }} />\n </DrawerFooter>\n )}\n </Drawer>\n );\n}\n\nDrawerController.openTrigger = '.js-acms-drawer-open';\nDrawerController.closeTrigger = '.js-acms-drawer-close';\n\nexport default DrawerController;\n","import { useRef, useState, useSyncExternalStore } from 'react';\nimport DrawerManager, { DrawerManagerOptions } from './drawer-manager';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface UseDrawerManagerOptions extends Partial<DrawerManagerOptions> {}\n\nexport default function useDrawerManager(options: UseDrawerManagerOptions = {}) {\n const mostRecentOptions = useRef(options);\n\n mostRecentOptions.current = options;\n const [manager] = useState(() => new DrawerManager(mostRecentOptions));\n\n const state = useSyncExternalStore(\n manager.subscribe,\n () => manager.getSnapshot(),\n () => manager.getSnapshot()\n );\n\n ACMS.Library.drawer = manager;\n\n return {\n state,\n manager,\n };\n}\n","import { pending } from '@ablogcms/pending';\nimport type Drawer from '@ablogcms/components/drawer';\nimport type { DrawerBody, DrawerFooter, DrawerHeader } from '@ablogcms/components/drawer';\nimport { fetchContentFromUrl, getContentFromSelector, patchFormActions } from '@ablogcms/modal/content-fetcher';\nimport SecurityManager, { SecurityConfig } from '@ablogcms/modal/security-manager';\n\ntype DrawerProps = Omit<React.ComponentProps<typeof Drawer>, 'onClose'>;\ntype DrawerHeaderProps = Omit<React.ComponentProps<typeof DrawerHeader>, 'children'>;\ntype DrawerBodyProps = Omit<React.ComponentProps<typeof DrawerBody>, 'children'>;\ntype DrawerFooterProps = Omit<React.ComponentProps<typeof DrawerFooter>, 'children'>;\n\nexport interface DrawerManagerState {\n content: Content;\n drawerProps: DrawerProps;\n drawerHeaderProps: DrawerHeaderProps;\n drawerBodyProps: DrawerBodyProps;\n drawerFooterProps: DrawerFooterProps;\n}\n\nexport interface DrawerManagerOptions {\n header: string;\n body: string;\n footer: string;\n security: Partial<SecurityConfig>;\n}\n\ninterface Content {\n header?: string;\n body?: string;\n footer?: string;\n raw: string;\n}\n\ninterface DrawerManagerOpenOptions {\n selector?: string;\n url?: string;\n drawerProps?: Partial<DrawerProps>;\n drawerHeaderProps?: Partial<DrawerHeaderProps>;\n drawerBodyProps?: Partial<DrawerBodyProps>;\n drawerFooterProps?: Partial<DrawerFooterProps>;\n}\n\nconst defaultOptions: DrawerManagerOptions = {\n header: '[data-drawer-section=\"header\"]',\n body: '[data-drawer-section=\"body\"]',\n footer: '[data-drawer-section=\"footer\"]',\n security: {},\n};\n\nclass DrawerManager {\n private listeners = new Set<() => void>();\n\n private state: DrawerManagerState = {\n content: {\n raw: '',\n },\n drawerProps: {\n isOpen: false,\n },\n drawerHeaderProps: {},\n drawerBodyProps: {},\n drawerFooterProps: {},\n };\n\n #container: HTMLElement | null = null;\n\n private config: DrawerManagerOptions = defaultOptions;\n\n private securityManager: SecurityManager;\n\n constructor(options: React.MutableRefObject<Partial<DrawerManagerOptions>>) {\n this.config = { ...defaultOptions, ...options.current };\n this.securityManager = new SecurityManager(this.config.security);\n this.handleSubmit = this.handleSubmit.bind(this);\n this.open = this.open.bind(this);\n this.close = this.close.bind(this);\n this.reset = this.reset.bind(this);\n this.init();\n }\n\n subscribe = (callback: () => void) => {\n this.listeners.add(callback);\n return () => this.listeners.delete(callback);\n };\n\n getSnapshot = () => this.state;\n\n public setState(state: DrawerManagerState | ((state: DrawerManagerState) => DrawerManagerState)) {\n if (typeof state === 'function') {\n this.state = state(this.state);\n } else {\n this.state = state;\n }\n this.emit();\n }\n\n public get content() {\n return this.state.content;\n }\n\n public get drawerProps() {\n return this.state.drawerProps;\n }\n\n public get drawerHeaderProps() {\n return this.state.drawerHeaderProps;\n }\n\n public get drawerBodyProps() {\n return this.state.drawerBodyProps;\n }\n\n public get drawerFooterProps() {\n return this.state.drawerFooterProps;\n }\n\n public get container() {\n return this.#container;\n }\n\n private init() {\n // ドロワー用のコンテナ要素を作成\n const container = document.getElementById('acms-drawer-manager-container');\n if (container !== null) {\n this.#container = container;\n } else {\n this.#container = document.createElement('div');\n this.#container.id = 'acms-drawer-manager-container';\n document.body.appendChild(this.#container);\n }\n this.registerEventListeners();\n }\n\n async open(options: DrawerManagerOpenOptions = {}) {\n const removeSplash = pending.splash(ACMS.i18n('splash.default'));\n try {\n // コンテンツ取得ユーティリティを使用\n const element = await this.fetchContent(options);\n\n // コンテンツをパース\n const content = this.parseContent(element);\n\n // 状態を更新\n this.setState({\n content,\n drawerProps: {\n ...options.drawerProps,\n isOpen: true,\n },\n drawerHeaderProps: {\n ...options.drawerHeaderProps,\n },\n drawerBodyProps: {\n ...options.drawerBodyProps,\n },\n drawerFooterProps: {\n ...options.drawerFooterProps,\n },\n });\n } catch (error) {\n console.error('Failed to open drawer:', error);\n // エラーを再スローして呼び出し元でハンドリングできるようにする\n throw error;\n } finally {\n removeSplash();\n }\n }\n\n close() {\n // 閉じるトランジション中は placement などの drawerProps を保持する必要があるため、\n // isOpen のみを切り替える。完全な初期化は reset() を onAfterClose 経由で呼ぶ\n this.setState((prev) => ({\n ...prev,\n drawerProps: {\n ...prev.drawerProps,\n isOpen: false,\n },\n }));\n }\n\n reset() {\n // 閉じるトランジション完了後に呼ばれることを想定し、コンテンツと props をクリアする\n this.setState({\n content: {\n raw: '',\n },\n drawerProps: {\n isOpen: false,\n },\n drawerHeaderProps: {},\n drawerBodyProps: {},\n drawerFooterProps: {},\n });\n }\n\n private emit = () => {\n this.listeners.forEach((cb) => cb());\n };\n\n // クリーンアップ用メソッド\n destroy() {\n this.unregisterEventListeners();\n if (this.#container) {\n this.#container.remove();\n this.#container = null;\n }\n }\n\n private async handleSubmit(event: SubmitEvent) {\n if (event.defaultPrevented) {\n // バリデーターがフォームの送信をキャンセルしている場合は、何もしない\n return;\n }\n event.preventDefault();\n const form = event.target as HTMLFormElement;\n const { submitter } = event;\n const formData = new FormData(form, submitter);\n\n let isSuccess = false;\n\n const removeSplash = pending.splash(ACMS.i18n('splash.save'));\n try {\n const response = await fetch(form.action, {\n method: form.method,\n body: formData,\n headers: {\n 'X-Requested-With': 'XMLHttpRequest',\n 'X-Csrf-Token': window.csrfToken || '',\n },\n });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n const html = await response.text();\n isSuccess = this.checkSuccessFromContent(html);\n const content = this.parseContent(patchFormActions(html, form.action));\n this.setState((prev) => ({\n ...prev,\n content,\n }));\n } catch (error) {\n console.error('Failed to submit form:', error);\n } finally {\n removeSplash();\n if (isSuccess) {\n setTimeout(() => {\n // 成功メッセージの表示が完了してから確認ダイアログを表示\n if (confirm(ACMS.i18n('drawer.reload'))) {\n window.location.reload();\n }\n }, 500);\n }\n }\n }\n\n private checkSuccessFromContent(html: string): boolean {\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n\n // 成功メッセージのセレクタを確認\n const successSelectors = [\n '.acms-admin-alert-info', // 成功アラート\n '.acms-admin-alert-success', // 成功アラート\n '[data-status=\"success\"]', // 成功ステータス\n '.success-message', // 成功メッセージ\n ];\n\n // エラーメッセージのセレクタを確認\n const errorSelectors = [\n '.acms-admin-alert-danger', // エラーアラート\n '.acms-admin-alert-error', // エラーアラート\n '[data-status=\"error\"]', // エラーステータス\n '.error-message', // エラーメッセージ\n ];\n\n // エラーメッセージが存在する場合は失敗\n for (const selector of errorSelectors) {\n if (doc.querySelector(selector)) {\n return false;\n }\n }\n\n // 成功メッセージが存在する場合は成功\n for (const selector of successSelectors) {\n if (doc.querySelector(selector)) {\n return true;\n }\n }\n\n // デフォルトは成功とみなす(エラーがない場合)\n return true;\n }\n\n private registerEventListeners() {\n this.#container?.addEventListener('submit', this.handleSubmit);\n }\n\n private unregisterEventListeners() {\n this.#container?.removeEventListener('submit', this.handleSubmit);\n }\n\n private parseContent(htmlContent: string) {\n const { header, body, footer } = this.config;\n const result: Content = {\n raw: htmlContent,\n };\n\n if (!header && !body && !footer) {\n // セレクタが指定されていない場合は、全体をボディとして扱う\n result.body = htmlContent;\n return result;\n }\n\n // 一時的なDOM要素を作成してHTMLを解析\n const div = document.createElement('div');\n div.innerHTML = htmlContent;\n\n // ヘッダーセクションの抽出\n if (header) {\n const headerElement = div.querySelector(header);\n if (headerElement) {\n result.header = headerElement.innerHTML;\n }\n }\n\n // ボディセクションの抽出\n if (body) {\n const bodyElement = div.querySelector(body);\n if (bodyElement) {\n result.body = bodyElement.innerHTML;\n }\n }\n\n // フッターセクションの抽出\n if (footer) {\n const footerElement = div.querySelector(footer);\n if (footerElement) {\n result.footer = footerElement.innerHTML;\n }\n }\n\n // セレクタが指定されていない場合は、対応するセクションに全体のコンテンツを設定\n if (!result.header && !result.body && !result.footer) {\n result.body = htmlContent;\n }\n\n return result;\n }\n\n private fetchContent(options: DrawerManagerOpenOptions) {\n const { selector, url } = options;\n\n if (selector) {\n return getContentFromSelector(selector);\n }\n\n if (url) {\n if (!this.securityManager.validateUrl(url)) {\n throw new Error(`URL is not allowed: ${url}`);\n }\n return fetchContentFromUrl(url);\n }\n\n throw new Error('No selector or URL provided');\n }\n}\n\nexport default DrawerManager;\n"],"mappings":"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","names":["useRef","useRef"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ablogcms/drawer",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.29",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Attribute-driven drawer controller for a-blog cms admin UI",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://www.a-blogcms.jp",
|
|
8
8
|
"repository": {
|
|
@@ -12,21 +12,22 @@
|
|
|
12
12
|
},
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@ablogcms/
|
|
16
|
-
"@ablogcms/
|
|
17
|
-
"@ablogcms/
|
|
18
|
-
"@ablogcms/
|
|
19
|
-
"@ablogcms/
|
|
20
|
-
"@ablogcms/
|
|
21
|
-
"@ablogcms/
|
|
15
|
+
"@ablogcms/components": "3.2.29",
|
|
16
|
+
"@ablogcms/pending": "3.2.29",
|
|
17
|
+
"@ablogcms/events": "3.2.29",
|
|
18
|
+
"@ablogcms/react-hooks": "3.2.29",
|
|
19
|
+
"@ablogcms/modal": "3.2.29",
|
|
20
|
+
"@ablogcms/react-utils": "3.2.29",
|
|
21
|
+
"@ablogcms/types": "3.2.29",
|
|
22
|
+
"@ablogcms/utils": "3.2.29"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"@testing-library/react": "^16.3.2",
|
|
25
|
-
"vitest": "^4.1.
|
|
26
|
+
"vitest": "^4.1.10"
|
|
26
27
|
},
|
|
27
28
|
"peerDependencies": {
|
|
28
29
|
"react": "^19",
|
|
29
|
-
"@types/react": "^19.2.
|
|
30
|
+
"@types/react": "^19.2.18"
|
|
30
31
|
},
|
|
31
32
|
"peerDependenciesMeta": {
|
|
32
33
|
"@types/react": {
|