hyperapp-is 0.1.8 → 0.1.9
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.
|
@@ -1,47 +1,22 @@
|
|
|
1
1
|
import { VNode, Effect } from "hyperapp";
|
|
2
2
|
import { Keys_NavigatorItem } from "./state";
|
|
3
|
-
/**
|
|
4
|
-
* ツリー構造となるナビゲーションオブジェクト
|
|
5
|
-
*
|
|
6
|
-
* parent - 親アイテム
|
|
7
|
-
* name - 名前
|
|
8
|
-
* properties - プロパティオブジェクト
|
|
9
|
-
* children - 子アイテムリスト (undefinedのときはファイル)
|
|
10
|
-
* path - パス
|
|
11
|
-
* extension - 拡張情報
|
|
12
|
-
*/
|
|
13
3
|
export interface NavigatorItem {
|
|
14
4
|
parent: NavigatorItem | null;
|
|
15
5
|
name: string;
|
|
6
|
+
path: string;
|
|
16
7
|
properties?: Record<string, any>;
|
|
17
8
|
children?: NavigatorItem[];
|
|
18
|
-
path: string;
|
|
19
9
|
extension?: Record<string, any>;
|
|
20
10
|
}
|
|
21
|
-
/**
|
|
22
|
-
* getEntriesで返すオブジェクト
|
|
23
|
-
*
|
|
24
|
-
* name - 名前
|
|
25
|
-
* data - データ
|
|
26
|
-
* isNode - ディレクトリか
|
|
27
|
-
*/
|
|
28
11
|
export interface JsonEntry<D> {
|
|
29
12
|
name: string;
|
|
30
13
|
data: D;
|
|
31
14
|
isNode: boolean;
|
|
32
15
|
}
|
|
33
|
-
/**
|
|
34
|
-
* ヘッダー名と値
|
|
35
|
-
*/
|
|
36
16
|
export interface NavigatorColumn {
|
|
37
17
|
name: string;
|
|
38
18
|
val: (item: NavigatorItem) => any;
|
|
39
19
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Json から NavigatorItem に変換
|
|
42
|
-
* getEntries の採用により、JSON の形を問わない
|
|
43
|
-
* extension により、任意情報を保存できる
|
|
44
|
-
*/
|
|
45
20
|
export declare const convertJsonToNavigatorItem: <D>(props: {
|
|
46
21
|
parent: NavigatorItem | null;
|
|
47
22
|
name: string;
|
|
@@ -51,15 +26,25 @@ export declare const convertJsonToNavigatorItem: <D>(props: {
|
|
|
51
26
|
depth?: number;
|
|
52
27
|
extension?: (item: NavigatorItem, data: D, depth: number) => Record<string, any> | undefined;
|
|
53
28
|
}) => NavigatorItem;
|
|
54
|
-
/**
|
|
55
|
-
* NavigatorItem の親をリストで取得する
|
|
56
|
-
*/
|
|
57
29
|
export declare const getParentItems: (item: NavigatorItem | undefined) => NavigatorItem[];
|
|
58
30
|
/**
|
|
59
|
-
*
|
|
31
|
+
* @template S
|
|
32
|
+
* @param props - props
|
|
33
|
+
*
|
|
34
|
+
* @param {S} props.state
|
|
35
|
+
* @param {string} props.id
|
|
36
|
+
* @param {Keys_NavigatorItem} props.currentKeys
|
|
37
|
+
* @param {(directory: NavigatorItem | undefined) => NavigatorColumn[]} [props.columns]
|
|
38
|
+
* @param {number} [props.maxItemsCount]
|
|
39
|
+
* @param {(state: S, item: NavigatorItem) => S | [S, Effect<S>]} [props.itemClick]
|
|
40
|
+
* @param {(props: {state: S, current?: NavigatorItem, extension?: Record<string, any>}, vnode: VNode<S>) => VNode<S>} [props.afterRender]
|
|
41
|
+
* @param {Record<string, any>} [props.extension]
|
|
42
|
+
*
|
|
43
|
+
* @returns {VNode<S>}
|
|
60
44
|
*/
|
|
61
45
|
export declare const NavigatorFinder: <S>(props: {
|
|
62
46
|
state: S;
|
|
47
|
+
id: string;
|
|
63
48
|
currentKeys: Keys_NavigatorItem;
|
|
64
49
|
columns?: (directory: NavigatorItem | undefined) => NavigatorColumn[];
|
|
65
50
|
maxItemsCount?: number;
|
|
@@ -1,28 +1,9 @@
|
|
|
1
1
|
// hyperapp-is / core / navigator.ts
|
|
2
|
-
import { getValue, setValue } from "./state";
|
|
3
|
-
import { el, deleteKeys } from "./component";
|
|
4
|
-
/* element */
|
|
5
|
-
const div = el("div");
|
|
6
|
-
const table = el("table");
|
|
7
|
-
const thead = el("thead");
|
|
8
|
-
const tbody = el("tbody");
|
|
9
|
-
const tr = el("tr");
|
|
10
|
-
const th = el("th");
|
|
11
|
-
const td = el("td");
|
|
12
|
-
const ul = el("ul");
|
|
13
|
-
const ol = el("ol");
|
|
14
|
-
const li = el("li");
|
|
15
|
-
const button = el("button");
|
|
16
|
-
const input = el("input");
|
|
17
|
-
const span = el("span");
|
|
2
|
+
import { getValue, setValue, getLocalState, setLocalState, createLocalKey } from "./state";
|
|
3
|
+
import { el, deleteKeys, SelectButton } from "./component";
|
|
18
4
|
// ---------- ---------- ---------- ---------- ----------
|
|
19
5
|
// convertJsonToNavigatorItem
|
|
20
6
|
// ---------- ---------- ---------- ---------- ----------
|
|
21
|
-
/**
|
|
22
|
-
* Json から NavigatorItem に変換
|
|
23
|
-
* getEntries の採用により、JSON の形を問わない
|
|
24
|
-
* extension により、任意情報を保存できる
|
|
25
|
-
*/
|
|
26
7
|
export const convertJsonToNavigatorItem = function (props) {
|
|
27
8
|
const { parent, name, data, getEntries, isNode, depth = 0, extension } = props;
|
|
28
9
|
const result = {
|
|
@@ -30,7 +11,6 @@ export const convertJsonToNavigatorItem = function (props) {
|
|
|
30
11
|
name,
|
|
31
12
|
path: parent ? parent.path + "/" + name : "/" + name
|
|
32
13
|
};
|
|
33
|
-
// 拡張情報
|
|
34
14
|
if (extension) {
|
|
35
15
|
const ext = extension(result, data, depth);
|
|
36
16
|
if (ext)
|
|
@@ -41,11 +21,9 @@ export const convertJsonToNavigatorItem = function (props) {
|
|
|
41
21
|
const children = [];
|
|
42
22
|
getEntries(data, depth).forEach(entry => {
|
|
43
23
|
const isProperty = typeof entry.data !== "object" || Array.isArray(entry.data);
|
|
44
|
-
// プロパティ
|
|
45
24
|
if (isProperty) {
|
|
46
25
|
properties[entry.name] = entry.data;
|
|
47
26
|
hasProperty = true;
|
|
48
|
-
// 子アイテム
|
|
49
27
|
}
|
|
50
28
|
else {
|
|
51
29
|
children.push(convertJsonToNavigatorItem({
|
|
@@ -62,15 +40,12 @@ export const convertJsonToNavigatorItem = function (props) {
|
|
|
62
40
|
if (hasProperty)
|
|
63
41
|
result.properties = properties;
|
|
64
42
|
if (isNode)
|
|
65
|
-
result.children = children;
|
|
43
|
+
result.children = children;
|
|
66
44
|
return result;
|
|
67
45
|
};
|
|
68
46
|
// ---------- ---------- ---------- ---------- ----------
|
|
69
47
|
// getParentItems
|
|
70
48
|
// ---------- ---------- ---------- ---------- ----------
|
|
71
|
-
/**
|
|
72
|
-
* NavigatorItem の親をリストで取得する
|
|
73
|
-
*/
|
|
74
49
|
export const getParentItems = (item) => {
|
|
75
50
|
if (!item)
|
|
76
51
|
return [];
|
|
@@ -83,16 +58,54 @@ export const getParentItems = (item) => {
|
|
|
83
58
|
return result.reverse();
|
|
84
59
|
};
|
|
85
60
|
// ---------- ---------- ---------- ---------- ----------
|
|
61
|
+
// vnodes
|
|
62
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
63
|
+
const div = el("div");
|
|
64
|
+
const table = el("table");
|
|
65
|
+
const thead = el("thead");
|
|
66
|
+
const tbody = el("tbody");
|
|
67
|
+
const tr = el("tr");
|
|
68
|
+
const th = el("th");
|
|
69
|
+
const td = el("td");
|
|
70
|
+
const ul = el("ul");
|
|
71
|
+
const ol = el("ol");
|
|
72
|
+
const li = el("li");
|
|
73
|
+
const button = el("button");
|
|
74
|
+
const input = el("input");
|
|
75
|
+
const span = el("span");
|
|
76
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
86
77
|
// NavigatorFinder Component
|
|
87
78
|
// ---------- ---------- ---------- ---------- ----------
|
|
88
79
|
/**
|
|
89
|
-
*
|
|
80
|
+
* @template S
|
|
81
|
+
* @param props - props
|
|
82
|
+
*
|
|
83
|
+
* @param {S} props.state
|
|
84
|
+
* @param {string} props.id
|
|
85
|
+
* @param {Keys_NavigatorItem} props.currentKeys
|
|
86
|
+
* @param {(directory: NavigatorItem | undefined) => NavigatorColumn[]} [props.columns]
|
|
87
|
+
* @param {number} [props.maxItemsCount]
|
|
88
|
+
* @param {(state: S, item: NavigatorItem) => S | [S, Effect<S>]} [props.itemClick]
|
|
89
|
+
* @param {(props: {state: S, current?: NavigatorItem, extension?: Record<string, any>}, vnode: VNode<S>) => VNode<S>} [props.afterRender]
|
|
90
|
+
* @param {Record<string, any>} [props.extension]
|
|
91
|
+
*
|
|
92
|
+
* @returns {VNode<S>}
|
|
90
93
|
*/
|
|
91
94
|
export const NavigatorFinder = function (props) {
|
|
92
95
|
var _a, _b;
|
|
93
|
-
|
|
96
|
+
// variable
|
|
97
|
+
const { state, id, currentKeys, maxItemsCount = 0, itemClick, afterRender, extension } = props;
|
|
94
98
|
const current = getValue(state, currentKeys, undefined);
|
|
99
|
+
// localState
|
|
100
|
+
const { searchText, selected } = getLocalState(state, id, {
|
|
101
|
+
searchText: "",
|
|
102
|
+
selected: []
|
|
103
|
+
});
|
|
104
|
+
// selected filter
|
|
105
|
+
const isFilter = selected.includes(`${createLocalKey(id)}_filter`);
|
|
106
|
+
// ---------- ---------- ----------
|
|
95
107
|
// createColumns
|
|
108
|
+
// ---------- ---------- ----------
|
|
96
109
|
const createColumns = (_a = props.columns) !== null && _a !== void 0 ? _a : ((directory) => {
|
|
97
110
|
const result = [];
|
|
98
111
|
if (!directory)
|
|
@@ -134,25 +147,60 @@ export const NavigatorFinder = function (props) {
|
|
|
134
147
|
const parentItems = getParentItems(current);
|
|
135
148
|
if (current)
|
|
136
149
|
parentItems.push(current);
|
|
150
|
+
// ---------- ---------- ----------
|
|
151
|
+
// hitTest
|
|
152
|
+
// ---------- ---------- ----------
|
|
153
|
+
const hitTest = (text) => {
|
|
154
|
+
const S = searchText.trim().toLowerCase();
|
|
155
|
+
if (S === "")
|
|
156
|
+
return false;
|
|
157
|
+
const keys = S.replace(/[ ]+/g, " ").split(" ").filter(Boolean);
|
|
158
|
+
if (keys.length === 0)
|
|
159
|
+
return false;
|
|
160
|
+
if (typeof text !== "string")
|
|
161
|
+
return false;
|
|
162
|
+
const sText = text.toLowerCase();
|
|
163
|
+
return keys.every(key => sText.includes(key));
|
|
164
|
+
}; // end hitTest
|
|
165
|
+
// ---------- ---------- ----------
|
|
137
166
|
// getItems
|
|
167
|
+
// ---------- ---------- ----------
|
|
138
168
|
const getItems = (item) => {
|
|
139
169
|
if (!item || item.children === undefined)
|
|
140
170
|
return [];
|
|
171
|
+
// filter
|
|
172
|
+
const result = isFilter && searchText !== ""
|
|
173
|
+
? item.children.filter(child => {
|
|
174
|
+
return columns.some(col => hitTest(col.val(child)));
|
|
175
|
+
})
|
|
176
|
+
: item.children;
|
|
177
|
+
// maxCount
|
|
141
178
|
const count = maxItemsCount === 0
|
|
142
|
-
?
|
|
143
|
-
: Math.min(maxItemsCount,
|
|
144
|
-
return
|
|
179
|
+
? result.length
|
|
180
|
+
: Math.min(maxItemsCount, result.length);
|
|
181
|
+
return result.slice(0, count);
|
|
145
182
|
}; // end getItems
|
|
146
183
|
// items
|
|
147
184
|
const items = getItems(current);
|
|
185
|
+
// items count
|
|
148
186
|
const count = current
|
|
149
187
|
? (_b = current.children) === null || _b === void 0 ? void 0 : _b.length
|
|
150
188
|
: 0;
|
|
189
|
+
// items hitCount
|
|
190
|
+
const hitCount = isFilter
|
|
191
|
+
? items.length
|
|
192
|
+
: items.filter(item => columns.some(col => hitTest(col.val(item)))).length;
|
|
193
|
+
// ---------- ---------- ----------
|
|
151
194
|
// action_parentClick
|
|
195
|
+
// ---------- ---------- ----------
|
|
152
196
|
const action_parentClick = (state, item) => {
|
|
153
|
-
return setValue(state, currentKeys, item)
|
|
197
|
+
return setLocalState(setValue(state, currentKeys, item), id, {
|
|
198
|
+
selected: []
|
|
199
|
+
});
|
|
154
200
|
};
|
|
201
|
+
// ---------- ---------- ----------
|
|
155
202
|
// action_itemClick
|
|
203
|
+
// ---------- ---------- ----------
|
|
156
204
|
const action_itemClick = (state, item) => {
|
|
157
205
|
// 子アイテムがすべてプロパティのときは移動しない
|
|
158
206
|
const children = item.children;
|
|
@@ -160,16 +208,54 @@ export const NavigatorFinder = function (props) {
|
|
|
160
208
|
return state;
|
|
161
209
|
if (!children.some(child => typeof child === "object" && !Array.isArray(child)))
|
|
162
210
|
return state;
|
|
163
|
-
|
|
211
|
+
// filterは解除する
|
|
212
|
+
return setLocalState(setValue(state, currentKeys, item), id, {
|
|
213
|
+
selected: []
|
|
214
|
+
});
|
|
164
215
|
};
|
|
216
|
+
// ---------- ---------- ----------
|
|
217
|
+
// action_inputSearchText
|
|
218
|
+
// ---------- ---------- ----------
|
|
219
|
+
const action_inputSearchText = (state, e) => {
|
|
220
|
+
const input = e.currentTarget;
|
|
221
|
+
if (!input)
|
|
222
|
+
return state;
|
|
223
|
+
return setLocalState(state, id, {
|
|
224
|
+
searchText: input.value
|
|
225
|
+
});
|
|
226
|
+
}; // end action_inputSearchText
|
|
227
|
+
// ---------- ---------- ----------
|
|
228
|
+
// action_copyFolderPath
|
|
229
|
+
// ---------- ---------- ----------
|
|
230
|
+
const action_copyFolderPath = (state) => {
|
|
231
|
+
if (!current)
|
|
232
|
+
return state;
|
|
233
|
+
navigator.clipboard.writeText(current.path);
|
|
234
|
+
return state;
|
|
235
|
+
}; // end action_copyFolderPath
|
|
236
|
+
// ---------- ---------- ----------
|
|
165
237
|
// VNode
|
|
238
|
+
// ---------- ---------- ----------
|
|
166
239
|
const vnode = div({
|
|
167
240
|
...deleteKeys(props, "state", "currentKeys", "columns", "itemClick", "afterRender", "extension")
|
|
168
241
|
},
|
|
169
242
|
// toolBar
|
|
170
243
|
div({
|
|
171
244
|
class: "toolBar"
|
|
172
|
-
},
|
|
245
|
+
}, input({
|
|
246
|
+
type: "text",
|
|
247
|
+
placeholder: "search keys",
|
|
248
|
+
value: searchText,
|
|
249
|
+
oninput: action_inputSearchText
|
|
250
|
+
}), SelectButton({
|
|
251
|
+
state: state,
|
|
252
|
+
id: `${createLocalKey(id)}_filter`,
|
|
253
|
+
keyNames: [createLocalKey(id), "selected"]
|
|
254
|
+
}, "FILTER"), button({
|
|
255
|
+
type: "button",
|
|
256
|
+
title: "現在のフォルダパスを、クリップボードにコピー",
|
|
257
|
+
onclick: action_copyFolderPath
|
|
258
|
+
}, "COPY")),
|
|
173
259
|
// parentItems
|
|
174
260
|
ol({}, parentItems.map(parent => li({
|
|
175
261
|
key: parent.path,
|
|
@@ -183,11 +269,15 @@ export const NavigatorFinder = function (props) {
|
|
|
183
269
|
: [action_itemClick, item]
|
|
184
270
|
}, columns.map(col => td({
|
|
185
271
|
title: col.val(item)
|
|
186
|
-
},
|
|
272
|
+
}, span({
|
|
273
|
+
class: hitTest(col.val(item)) ? "hit" : ""
|
|
274
|
+
}, col.val(item)))))))),
|
|
187
275
|
// statusBar
|
|
188
276
|
div({
|
|
189
277
|
class: "statusBar"
|
|
190
|
-
}, `items ${items.length} / ${count}`));
|
|
278
|
+
}, `items ${items.length} / ${count}` + (searchText !== "" ? ` (${hitCount} hit)` : "")));
|
|
279
|
+
// ---------- ---------- ----------
|
|
191
280
|
// afterRender
|
|
281
|
+
// ---------- ---------- ----------
|
|
192
282
|
return afterRender ? afterRender({ state, current, extension }, vnode) : vnode;
|
|
193
283
|
};
|