@lism-css/ui 0.1.0 → 0.1.1
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/components/Accordion/setAccordion.d.ts +1 -1
- package/dist/components/Accordion/setAccordion.js +39 -28
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/components/Accordion/_style.css +5 -5
- package/src/components/Accordion/react/Accordion.jsx +0 -6
- package/src/components/Accordion/setAccordion.js +76 -63
|
@@ -1,37 +1,48 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
const
|
|
20
|
-
|
|
1
|
+
const l = (e) => {
|
|
2
|
+
const t = e.querySelector(".d--accordion_body"), n = t ? t.getAnimations() : [];
|
|
3
|
+
return Promise.allSettled(n.map((o) => o.finished));
|
|
4
|
+
}, s = async (e) => {
|
|
5
|
+
e.open && e.hasAttribute("data-opened") || (e.open = !0, requestAnimationFrame(() => {
|
|
6
|
+
e.setAttribute("data-opened", "");
|
|
7
|
+
}));
|
|
8
|
+
}, a = async (e) => {
|
|
9
|
+
!e.open && !e.hasAttribute("data-opened") || (e.removeAttribute("data-opened"), await l(e), e.open = !1);
|
|
10
|
+
}, i = (e) => {
|
|
11
|
+
let t = !1;
|
|
12
|
+
const n = e.parentNode;
|
|
13
|
+
return n != null && (t = n.dataset.multiple !== "disallow"), t;
|
|
14
|
+
}, p = (e, t) => {
|
|
15
|
+
if (e.open)
|
|
16
|
+
e.open && a(e);
|
|
17
|
+
else {
|
|
18
|
+
if (!t) {
|
|
19
|
+
const o = e.parentNode.querySelector("[data-opened]");
|
|
20
|
+
requestAnimationFrame(() => {
|
|
21
|
+
o != null && a(o);
|
|
22
|
+
});
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
24
|
+
s(e);
|
|
25
|
+
}
|
|
26
|
+
}, u = (e) => {
|
|
27
|
+
const t = e.open, n = e.hasAttribute("data-opened");
|
|
28
|
+
t && !n && e.setAttribute("data-opened", ""), !t && n && e.removeAttribute("data-opened");
|
|
29
|
+
}, d = (e) => {
|
|
30
|
+
const t = i(e), n = e.querySelector("summary");
|
|
31
|
+
if (!n) return;
|
|
32
|
+
const o = (c) => {
|
|
33
|
+
c.preventDefault(), p(e, t);
|
|
34
|
+
}, r = () => {
|
|
35
|
+
u(e);
|
|
25
36
|
};
|
|
26
|
-
return n.addEventListener("click",
|
|
27
|
-
n.removeEventListener("click",
|
|
37
|
+
return n.addEventListener("click", o), e.addEventListener("toggle", r), () => {
|
|
38
|
+
n.removeEventListener("click", o), e.removeEventListener("toggle", r);
|
|
28
39
|
};
|
|
29
40
|
}, m = () => {
|
|
30
|
-
document.querySelectorAll(".d--accordion").forEach((
|
|
31
|
-
|
|
41
|
+
document.querySelectorAll(".d--accordion").forEach((t) => {
|
|
42
|
+
d(t);
|
|
32
43
|
});
|
|
33
44
|
};
|
|
34
45
|
export {
|
|
35
46
|
m as default,
|
|
36
|
-
|
|
47
|
+
d as setEvent
|
|
37
48
|
};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer lism.modules{.d--accordion{--duration:var(--acc-duration,0.
|
|
1
|
+
@layer lism.modules{.d--accordion{--duration:var(--acc-duration,0.25s)}.d--accordion[data-opened]{--_notOpen: }.d--accordion:not([data-opened]){--_isOpen: }.d--accordion_header{align-items:center;display:grid;gap:.5em;grid:auto/1fr auto;--focus-offset:-1px;&::-webkit-details-marker{display:none}}.d--accordion_body{display:grid;grid:1fr/auto;transition-duration:var(--duration);transition-property:margin-block,padding-block,opacity,grid-template}.d--accordion_inner{overflow:hidden}.d--accordion:not([data-opened])>.d--accordion_body{grid:0fr/auto;margin-block:0!important;padding-block:0!important}.d--accordion_icon{display:grid}.d--accordion_icon>.a--icon{transform:var(--_isOpen,scaleY(-1));transition:transform var(--duration)}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lism-css/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "UI components by lism-css.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ddryo",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"url": "https://github.com/lism-css/lism-css/issues"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"lism-css": "0.8.
|
|
42
|
+
"lism-css": "0.8.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@babel/cli": "^7.27.2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@layer lism.modules {
|
|
2
2
|
.d--accordion {
|
|
3
|
-
--duration: var(--acc-duration, 0.
|
|
3
|
+
--duration: var(--acc-duration, 0.25s);
|
|
4
4
|
}
|
|
5
5
|
.d--accordion[data-opened] {
|
|
6
6
|
--_notOpen: ;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
grid: auto / 1fr auto;
|
|
15
15
|
gap: 0.5em;
|
|
16
16
|
align-items: center;
|
|
17
|
-
|
|
17
|
+
--focus-offset: -1px; /* overflow:hidden; で見えなくなってしまいがちなので内側に寄せておく */
|
|
18
18
|
|
|
19
19
|
/* Safariで表示されるデフォルトの三角形アイコンを消す */
|
|
20
20
|
&::-webkit-details-marker {
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/* .d--accordion_icon 自体にborderつけたりすると回転が見えてしまうので、中にある .a--icon を回転させる。 */
|
|
50
|
-
.d--accordion_icon .a--icon {
|
|
51
|
-
transition
|
|
52
|
-
|
|
50
|
+
.d--accordion_icon > .a--icon {
|
|
51
|
+
transition: transform var(--duration);
|
|
52
|
+
transform: var(--_isOpen, scaleY(-1));
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -7,9 +7,6 @@ import AccIcon from './AccIcon';
|
|
|
7
7
|
|
|
8
8
|
import '../_style.css';
|
|
9
9
|
|
|
10
|
-
// import { AccContext } from './context';
|
|
11
|
-
|
|
12
|
-
// duration: [s]
|
|
13
10
|
export function Accordion({ children, ...props }) {
|
|
14
11
|
const ref = React.useRef(null);
|
|
15
12
|
|
|
@@ -22,12 +19,10 @@ export function Accordion({ children, ...props }) {
|
|
|
22
19
|
|
|
23
20
|
return (
|
|
24
21
|
<details ref={ref} {...lismProps}>
|
|
25
|
-
{/* <AccContext.Provider value={deliverState}>{children}</AccContext.Provider> */}
|
|
26
22
|
{children}
|
|
27
23
|
</details>
|
|
28
24
|
);
|
|
29
25
|
}
|
|
30
|
-
|
|
31
26
|
export function Header({ children, ...props }) {
|
|
32
27
|
return (
|
|
33
28
|
<Lism tag='summary' {...defaultProps.header} {...props}>
|
|
@@ -42,7 +37,6 @@ export function Label({ children, ...props }) {
|
|
|
42
37
|
</Lism>
|
|
43
38
|
);
|
|
44
39
|
}
|
|
45
|
-
|
|
46
40
|
export function Body({ children, flow, innerProps, ...props }) {
|
|
47
41
|
return (
|
|
48
42
|
<Lism {...defaultProps.body} {...props}>
|
|
@@ -1,99 +1,112 @@
|
|
|
1
|
-
//
|
|
2
|
-
const
|
|
1
|
+
// アニメーションが完了するのを待つ
|
|
2
|
+
const waitAnimation = (details) => {
|
|
3
|
+
// アニメーション対象の要素を直接取得.(getAnimations({subtree: true}) は iOS Safari で動作しない場合があるので __body を直接監視)
|
|
4
|
+
const body = details.querySelector('.d--accordion_body');
|
|
5
|
+
const animations = body ? body.getAnimations() : [];
|
|
3
6
|
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
return Promise.all(element.getAnimations().map((a) => a.finished));
|
|
7
|
+
// allSettled を使うことで、キャンセル時も reject せずに完了する
|
|
8
|
+
return Promise.allSettled(animations.map((a) => a.finished));
|
|
7
9
|
};
|
|
8
10
|
|
|
9
11
|
// animationTime: [ms]
|
|
10
|
-
const
|
|
11
|
-
//
|
|
12
|
-
if (details.
|
|
13
|
-
details.dataset.animating = '1';
|
|
12
|
+
const open = async (details) => {
|
|
13
|
+
// すでに開いている場合は何もしない
|
|
14
|
+
if (details.open && details.hasAttribute('data-opened')) return;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
// open属性をセット
|
|
17
|
+
details.open = true;
|
|
16
18
|
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
details.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} else if (details.open) {
|
|
29
|
-
details.removeAttribute('data-opened'); // クラスを削除
|
|
19
|
+
// 次フレームで data-opened 属性を付与(CSS側でフェードインアニメーション開始)
|
|
20
|
+
requestAnimationFrame(() => {
|
|
21
|
+
details.setAttribute('data-opened', ''); // 属性の追加
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const close = async (details) => {
|
|
26
|
+
// すでに閉じている場合は何もしない
|
|
27
|
+
if (!details.open && !details.hasAttribute('data-opened')) return;
|
|
28
|
+
|
|
29
|
+
details.removeAttribute('data-opened'); // 属性を削除
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// アニメーションを待つ
|
|
32
|
+
await waitAnimation(details);
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// アニメーション完了後にopen属性 を除去。
|
|
35
|
+
details.open = false;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// 複数展開を許可するかどうかを、親要素の [data-multiple] でチェック.
|
|
39
|
+
const getAllowMultiple = (details) => {
|
|
40
|
+
let allowMultiple = false;
|
|
41
|
+
const parent = details.parentNode;
|
|
42
|
+
if (null != parent) {
|
|
43
|
+
const dataMultiple = parent.dataset.multiple;
|
|
44
|
+
allowMultiple = 'disallow' !== dataMultiple;
|
|
36
45
|
}
|
|
46
|
+
return allowMultiple;
|
|
37
47
|
};
|
|
38
48
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
const onClick = (details, allowMultiple) => {
|
|
50
|
+
if (!details.open) {
|
|
51
|
+
if (!allowMultiple) {
|
|
52
|
+
// (複数展開が禁止されている場合)他の開いているアイテムがあるかどうかを先に探して閉じる
|
|
53
|
+
const parent = details.parentNode;
|
|
54
|
+
const openedItem = parent.querySelector(`[data-opened]`);
|
|
55
|
+
requestAnimationFrame(() => {
|
|
56
|
+
// 1フレーム待機(safariでは requestAnimationFrame() がないと動かなかった)
|
|
57
|
+
if (null != openedItem) close(openedItem);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 開く処理
|
|
62
|
+
open(details);
|
|
63
|
+
} else if (details.open) {
|
|
64
|
+
// 閉じる処理
|
|
65
|
+
close(details);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
42
68
|
|
|
69
|
+
const onToggle = (details) => {
|
|
43
70
|
const hasOpen = details.open;
|
|
44
|
-
const
|
|
71
|
+
const hasDataOpen = details.hasAttribute('data-opened');
|
|
45
72
|
|
|
46
|
-
// open はセットされたのに data-opened
|
|
47
|
-
if (hasOpen && !
|
|
73
|
+
// open はセットされたのに data-opened 属性がついてない時
|
|
74
|
+
if (hasOpen && !hasDataOpen) {
|
|
48
75
|
details.setAttribute('data-opened', '');
|
|
49
76
|
}
|
|
50
|
-
// open は削除されたのに data-opened
|
|
51
|
-
if (!hasOpen &&
|
|
77
|
+
// open は削除されたのに data-opened 属性がまだついている時
|
|
78
|
+
if (!hasOpen && hasDataOpen) {
|
|
52
79
|
details.removeAttribute('data-opened');
|
|
53
80
|
}
|
|
54
81
|
};
|
|
55
82
|
|
|
56
|
-
export const setEvent = (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const clickBtn = details.querySelector(`[data-role="trigger"]`) || details.querySelector('summary');
|
|
83
|
+
export const setEvent = (details) => {
|
|
84
|
+
// 複数展開を制限するかどうか
|
|
85
|
+
const allowMultiple = getAllowMultiple(details);
|
|
60
86
|
|
|
61
|
-
|
|
87
|
+
// <summary> 要素をトリガーとする
|
|
88
|
+
const summary = details.querySelector('summary');
|
|
89
|
+
if (!summary) return;
|
|
62
90
|
|
|
63
|
-
|
|
64
|
-
let allowMultiple = false;
|
|
65
|
-
const parent = details.parentNode;
|
|
66
|
-
if (null != parent) {
|
|
67
|
-
const dataMultiple = parent.dataset.accordionMultiple;
|
|
68
|
-
allowMultiple = 'disallow' !== dataMultiple;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const _clickedEvent = (e) => {
|
|
91
|
+
const _clickEvent = (e) => {
|
|
72
92
|
// すぐに open 属性が切り替わらないようにする
|
|
73
93
|
e.preventDefault();
|
|
74
|
-
|
|
75
|
-
// 複数展開が禁止されている場合、(開く処理の直前で)他の開いているアイテムがあれば閉じる
|
|
76
|
-
if (!allowMultiple && !details.open) {
|
|
77
|
-
const openedItem = parent.querySelector(`[data-opened]`);
|
|
78
|
-
if (null != openedItem) clickedEvent(openedItem, true);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 自身のクリック処理
|
|
82
|
-
clickedEvent(details);
|
|
94
|
+
onClick(details, allowMultiple);
|
|
83
95
|
};
|
|
84
|
-
const _toggleEvent = (
|
|
85
|
-
|
|
96
|
+
const _toggleEvent = () => {
|
|
97
|
+
onToggle(details);
|
|
86
98
|
};
|
|
87
99
|
|
|
88
100
|
// <summary> 'click' イベント
|
|
89
|
-
|
|
101
|
+
summary.addEventListener('click', _clickEvent);
|
|
90
102
|
|
|
91
103
|
// <details> の'toggle' イベントで、ページ内検索時にも開閉されるようにする
|
|
92
104
|
details.addEventListener('toggle', _toggleEvent);
|
|
93
105
|
|
|
94
|
-
//
|
|
106
|
+
// react用
|
|
95
107
|
return () => {
|
|
96
|
-
|
|
108
|
+
// useEffect でアンマウントされた時にremoveEventListenerしないと2重でイベントが登録してしまう。
|
|
109
|
+
summary.removeEventListener('click', _clickEvent);
|
|
97
110
|
details.removeEventListener('toggle', _toggleEvent);
|
|
98
111
|
};
|
|
99
112
|
};
|