import { defineComponent } from 'vue';
import { getStoreState } from '../store/StoreControl';
import {
EMPTY_OBJECT,
EMPTY_DATA_BIND_INFO,
DataBinderInfo,
resolvePath,
GetViewStateMethod,
DataBindInfoInjectedInstance,
} from './helper';
/** provide情報キー */
export const PROVIDE_DATA_BIND_INFO_NAME = 'parentDataBindInfo';
/**
* 利用者で実装する Vue メソッド
*/
interface VueUserImplements {
/** provide として設定する情報を返却する */
getProvideViewState?: GetViewStateMethod;
}
/**
* # StorePathMixin
*
* ## ソースコード
*
* [src/mixins/StorePathMixin.ts](../../src/mixins/StorePathMixin.ts)
*
* ## Doclet
*
* store 値までのパスを定義する mixin。
*
* @remarks
*
* ### 概要
*
* - Store state のデータのパスをコントロールする。
* - path 情報は、vue 機能の provide/inject を利用し、下位コンポーネントへ伝達する。
*
* ### 使用方法
*
* - パスを指定したいコンポーネントの mixin に組み込む。
* - mData, mViewState でモジュールを指定する場合は、先頭に `moduleName:` を指定する。
* - 例: `moduleName:path.to`
*
* ### mixin 詳細
*
* | No | vue type | name | value type | desc | remarks |
* | --: | -------- | ----------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------- |
* | 1 | props | mData | string | data を定義した state パス要素。 | |
* | 2 | props | mViewState | string | viewState を定義した state パス要素。 | |
* | 3 | props | mNotInheritData | boolean | 上位の dataPath を継承するか。true の場合継承しない。 | default value = false |
* | 4 | props | mNotInheritViewState | boolean | 上位の viewStatePath を継承するか。true の場合継承しない。 | default value = false |
* | 5 | computed | parentInfo | DataBinderInfo | 上位から引き継がれた `DataBinderInfo`。inject で指定された値。 | |
* | 6 | computed | provideDataPath | DataBinderInfo | parentInfo.dataPath + '.' + mData の値。 | |
* | 7 | computed | provideViewStatePath | DataBinderInfo | parentInfo.viewStatePath + '.' + mViewState の値。 | |
* | 8 | methods | parentViewState | any | parentInfo.viewState() の値。mNotInheritViewState が true の場合、空オブジェクトとなる。 | generics 利用可能。 |
* | 9 | methods | currentViewState | any | provideViewStatePath に一致した store の viewState を取得。 | generics 利用可能。 |
* | 10 | methods | provideViewState | any | 下位へ引き継ぐ viewState。getProvideViewState の返却値を設定する。getProvideViewState 未実装の場合は currentViewState を返却。 | generics 利用可能。 |
* | 11 | methods | getProvideViewState | any | 下位へ引き継ぐ viewState の値を返却する。mixin では未実装。拡張ポイント。 | 利用者にて実装する。 |
*
* ### パス要素継承例
*
* ```html
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* ```
*
* 上記の設定状況の場合の、継承状況や項目設定状況
*
* | No | type | props mData | props mViewState | prop mId | remarks | provideDataPath \| dataId | provideViewStatePath \| viewStateId |
* | --: | ---------- | ----------------- | ----------------------- | ----------- | ---------------------------------------------------------------------------------------------- | ------------------------- | ----------------------------------- |
* | A | store-path | dataKey.data.path | viewStateKey.case1.path | - | 最上位パス定義。 | dataKey.data.path | viewStateKey.case.path |
* | B | store-path | to | | - | dataPath, viewStatePath を上位から継承。自身の mData, mViewState は上位の値と連結。 | dataKey.data.path.to | viewStateKey.case.path |
* | C | store-bind | - | - | id1 | dataPath, viewStatePath を上位から継承。自身の mId を 上位の (data\|viewState)Path と連結。 | dataKey.data.path.to.id1 | viewStateKey.case.path.id1 |
* | D | store-path | module1:hoge | module1:viewState.hoge | - | mNotInheritData, mNotInheritViewState 指定の為、本要素で指定した値のみ有効。 | module1:hoge | module1:viewState.hoge |
* | E | store-bind | - | - | huga | dataPath, viewStatePath を上位から継承。自身の mId を 上位の (data\|viewState)Path と連結。 | module1:hoge.huga | module1:viewState.hoge.huga |
*
* @example
*
* ### 実装例
*
* ```vue
*
*
*
*
*
*
*
*
* ```
*/
export default defineComponent({
name: 'StorePathMixin',
inject: {
dataBindInfo: {
from: PROVIDE_DATA_BIND_INFO_NAME,
default: () => EMPTY_DATA_BIND_INFO,
},
},
provide() {
const dataPathFn = (): string | undefined => this.provideDataPath;
const viewStatePathFn = (): string | undefined => this.provideViewStatePath;
const viewStateFn = (): S => this.provideViewState();
return {
[PROVIDE_DATA_BIND_INFO_NAME]: {
dataPath() {
return dataPathFn();
},
viewStatePath() {
return viewStatePathFn();
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ViewStateデータは任意でどのような値でも指定可能な為、any を許容する
viewState() {
return viewStateFn();
},
} as DataBinderInfo,
};
},
props: {
mData: {
type: String,
required: false,
default: undefined,
},
mViewState: {
type: String,
required: false,
default: undefined,
},
mNotInheritData: {
type: Boolean,
require: false,
default: false,
},
mNotInheritViewState: {
type: Boolean,
require: false,
default: false,
},
},
computed: {
parentInfo(): DataBinderInfo {
return (this as unknown as DataBindInfoInjectedInstance).dataBindInfo;
},
provideDataPath(): string | undefined {
if (this.mNotInheritData) {
return this.mData;
}
return resolvePath(this.parentInfo.dataPath(), this.mData);
},
provideViewStatePath(): string | undefined {
if (this.mNotInheritViewState) {
return this.mViewState;
}
return resolvePath(this.parentInfo.viewStatePath(), this.mViewState);
},
},
methods: {
/**
* 上位の viewState を取得する。
* 上位の情報は inject で設定された情報を使用する。
*
* @returns 親 viewState 値
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ViewStateデータは任意でどのような値でも指定可能な為、any を許容する
parentViewState(): S {
if (this.mNotInheritViewState) {
// viewState を継承しない場合は、空オブジェクトを返却する
return EMPTY_OBJECT;
}
return this.parentInfo.viewState();
},
/**
* 現在パスの viewState の値を store state から取得する
* @see {@link provideViewStatePath}
* @returns 現在パスの viewState 値
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ViewStateデータは任意でどのような値でも指定可能な為、any を許容する
currentViewState(): S {
const path = this.provideViewStatePath;
if (!path) {
// path = undefined の場合は空オブジェクトを返却する
return EMPTY_OBJECT;
}
// パスが設定されていた場合は、viewState を返却する
return getStoreState(this.$store.state, path);
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ViewStateデータは任意でどのような値でも指定可能な為、any を許容する
provideViewState(): S {
const userImplementsInst = this as unknown as VueUserImplements;
// 利用者が実装する getProvideViewState メソッドが存在していたら呼び出す
if (userImplementsInst.getProvideViewState) {
return userImplementsInst.getProvideViewState();
}
// 無ければ現在の表示状態を返却する
return this.currentViewState();
},
},
});