hyperapp-is 0.1.7 → 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.
- package/README.md +5 -7
- package/dist/hyperapp-is/core/navigator.d.ts +15 -30
- package/dist/hyperapp-is/core/navigator.js +128 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -532,16 +532,14 @@ getEntriesの返す値
|
|
|
532
532
|
|
|
533
533
|
```ts
|
|
534
534
|
export interface JsonEntry <D> {
|
|
535
|
-
name
|
|
536
|
-
data
|
|
537
|
-
|
|
538
|
-
isNode : boolean
|
|
535
|
+
name : string
|
|
536
|
+
data : D
|
|
537
|
+
isNode: boolean
|
|
539
538
|
}
|
|
540
539
|
```
|
|
541
540
|
|
|
542
541
|
- name : 名前
|
|
543
542
|
- data : データ
|
|
544
|
-
- isProperty: プロパティか
|
|
545
543
|
- isNode : ディレクトリか
|
|
546
544
|
|
|
547
545
|
---
|
|
@@ -609,7 +607,7 @@ export const NavigatorFinder = function <S> (
|
|
|
609
607
|
props: {
|
|
610
608
|
state : S
|
|
611
609
|
currentKeys : Keys_NavigatorItem
|
|
612
|
-
columns ?: NavigatorColumn[]
|
|
610
|
+
columns ?: (directory: NavigatorItem | undefined) => NavigatorColumn[]
|
|
613
611
|
maxItemsCount?: number
|
|
614
612
|
itemClick ?: (state: S, item: NavigatorItem) => S | [S, Effect<S>]
|
|
615
613
|
afterRender ?: (props: {
|
|
@@ -625,7 +623,7 @@ export const NavigatorFinder = function <S> (
|
|
|
625
623
|
|
|
626
624
|
- state : ステート
|
|
627
625
|
- currentKeys : カレント NavigatorItem までのパス
|
|
628
|
-
- columns : NavigatorColumn
|
|
626
|
+
- columns : NavigatorColumn の配列を返す関数
|
|
629
627
|
- maxItemsCount: 最大表示するアイテム数
|
|
630
628
|
- itemClick : アイテムをクリックした時のアクション
|
|
631
629
|
- afterRender : レンダーフック
|
|
@@ -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)
|
|
@@ -109,8 +122,6 @@ export const NavigatorFinder = function (props) {
|
|
|
109
122
|
// get properties
|
|
110
123
|
// 子アイテムのプロパティをすべて確認して抽出しています
|
|
111
124
|
children.forEach(child => {
|
|
112
|
-
if (!child.children)
|
|
113
|
-
return;
|
|
114
125
|
if (child.properties) {
|
|
115
126
|
Object.keys(child.properties).forEach(key => names.push(key));
|
|
116
127
|
}
|
|
@@ -136,25 +147,60 @@ export const NavigatorFinder = function (props) {
|
|
|
136
147
|
const parentItems = getParentItems(current);
|
|
137
148
|
if (current)
|
|
138
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
|
+
// ---------- ---------- ----------
|
|
139
166
|
// getItems
|
|
167
|
+
// ---------- ---------- ----------
|
|
140
168
|
const getItems = (item) => {
|
|
141
169
|
if (!item || item.children === undefined)
|
|
142
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
|
|
143
178
|
const count = maxItemsCount === 0
|
|
144
|
-
?
|
|
145
|
-
: Math.min(maxItemsCount,
|
|
146
|
-
return
|
|
179
|
+
? result.length
|
|
180
|
+
: Math.min(maxItemsCount, result.length);
|
|
181
|
+
return result.slice(0, count);
|
|
147
182
|
}; // end getItems
|
|
148
183
|
// items
|
|
149
184
|
const items = getItems(current);
|
|
185
|
+
// items count
|
|
150
186
|
const count = current
|
|
151
187
|
? (_b = current.children) === null || _b === void 0 ? void 0 : _b.length
|
|
152
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
|
+
// ---------- ---------- ----------
|
|
153
194
|
// action_parentClick
|
|
195
|
+
// ---------- ---------- ----------
|
|
154
196
|
const action_parentClick = (state, item) => {
|
|
155
|
-
return setValue(state, currentKeys, item)
|
|
197
|
+
return setLocalState(setValue(state, currentKeys, item), id, {
|
|
198
|
+
selected: []
|
|
199
|
+
});
|
|
156
200
|
};
|
|
201
|
+
// ---------- ---------- ----------
|
|
157
202
|
// action_itemClick
|
|
203
|
+
// ---------- ---------- ----------
|
|
158
204
|
const action_itemClick = (state, item) => {
|
|
159
205
|
// 子アイテムがすべてプロパティのときは移動しない
|
|
160
206
|
const children = item.children;
|
|
@@ -162,16 +208,54 @@ export const NavigatorFinder = function (props) {
|
|
|
162
208
|
return state;
|
|
163
209
|
if (!children.some(child => typeof child === "object" && !Array.isArray(child)))
|
|
164
210
|
return state;
|
|
165
|
-
|
|
211
|
+
// filterは解除する
|
|
212
|
+
return setLocalState(setValue(state, currentKeys, item), id, {
|
|
213
|
+
selected: []
|
|
214
|
+
});
|
|
166
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
|
+
// ---------- ---------- ----------
|
|
167
237
|
// VNode
|
|
238
|
+
// ---------- ---------- ----------
|
|
168
239
|
const vnode = div({
|
|
169
240
|
...deleteKeys(props, "state", "currentKeys", "columns", "itemClick", "afterRender", "extension")
|
|
170
241
|
},
|
|
171
242
|
// toolBar
|
|
172
243
|
div({
|
|
173
244
|
class: "toolBar"
|
|
174
|
-
},
|
|
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")),
|
|
175
259
|
// parentItems
|
|
176
260
|
ol({}, parentItems.map(parent => li({
|
|
177
261
|
key: parent.path,
|
|
@@ -185,11 +269,15 @@ export const NavigatorFinder = function (props) {
|
|
|
185
269
|
: [action_itemClick, item]
|
|
186
270
|
}, columns.map(col => td({
|
|
187
271
|
title: col.val(item)
|
|
188
|
-
},
|
|
272
|
+
}, span({
|
|
273
|
+
class: hitTest(col.val(item)) ? "hit" : ""
|
|
274
|
+
}, col.val(item)))))))),
|
|
189
275
|
// statusBar
|
|
190
276
|
div({
|
|
191
277
|
class: "statusBar"
|
|
192
|
-
}, `items ${items.length} / ${count}`));
|
|
278
|
+
}, `items ${items.length} / ${count}` + (searchText !== "" ? ` (${hitCount} hit)` : "")));
|
|
279
|
+
// ---------- ---------- ----------
|
|
193
280
|
// afterRender
|
|
281
|
+
// ---------- ---------- ----------
|
|
194
282
|
return afterRender ? afterRender({ state, current, extension }, vnode) : vnode;
|
|
195
283
|
};
|