LoadingRegion
์์ง ๋ด์ฉ์ด ์ค์ง ์์ ์์ญ์ "๋ก๋ฉ ์ค" ์ ํ ๋ฒ๋ง ์๋ฆฌ๋ ๋ํผ
๋ชฉ์ฐจ
ํ ์์ญ์ ์ฑ์ฐ๋ ์ค์ผ๋ ํค๋ค์ ๊ฐ์ธ "๋ก๋ฉ ์ค" ์ ์์ญ ๋จ์๋ก ํ ๋ฒ ์๋ฆฝ๋๋ค. ์์ชฝ ์ค์ผ๋ ํค์ ์๊ธฐ๊ฐ ์์ญ ์์ ์์์ ์๊ณ ์๊ธฐ ์๋ฆผ์ ๋๋๋ค โ ์ค์ผ๋ ํค ์ด ๊ฐ๊ฐ ์๋ฆผ ์ด ๋ฒ์ด ๋์ง ์์ต๋๋ค. ํ๋ฉด์ ๊ทธ๋ฆฌ๋ ๊ฒ์ ์์ต๋๋ค. ๋ ์ด์์ ์์(flex ยท grid ยท flow)๋
child ๊ทธ๋๋ก์
๋๋ค โ Web ์์ ๋ถ๋ชจ์ ํ์ ์ ํ์ ๊ธฐ๋ฐ ๊ฐ๊ฒฉ(space-y-* ยท divide-*)๋ง ์์ญ์ ์ง๋
child ์ ๋ฟ์ง ์์ผ๋ฏ๋ก, ์์ญ์ ๋ถ๋ชจ์๋ gap ์ ์ฐ์ธ์.
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ (Basic Usage)#
LoadingRegion(
semanticLabel: '์ฃผ๋ฌธ ๋ชฉ๋ก ๋ถ๋ฌ์ค๋ ์ค',
child: Column(
spacing: CoreSpace.space8,
children: [
Skeleton(height: 20),
Skeleton(height: 20),
Skeleton(height: 20),
],
),
)
๋ก๋ฉ์ด ๋๋๋ฉด ํธ์ถํ๋ ์ชฝ ์กฐ๊ฑด์ผ๋ก ์์ญ์งธ ์ค์ ๋ด์ฉ์ผ๋ก ๋ฐ๊ฟ๋๋ค.
isLoading
? LoadingRegion(child: orderSkeletons)
: OrderList(orders: orders)
Live Preview#
์ฝ๋ ๋ณด๊ธฐ
class LoadingRegionDefaultExample extends StatefulComponent {
const LoadingRegionDefaultExample({super.key});
@override
State<LoadingRegionDefaultExample> createState() => _LoadingRegionDefaultExampleState();
}
class _LoadingRegionDefaultExampleState extends State<LoadingRegionDefaultExample> {
@override
Component build(BuildContext context) {
return LoadingRegion(
semanticLabel: 'Loading orders',
child: div(classes: 'flex flex-col gap-${CoreSpace.scale.space8}', [
Skeleton(width: '200px', height: '20px'),
Skeleton(width: '150px', height: '20px'),
Skeleton(width: '180px', height: '20px'),
]),
);
}
}
class LoadingRegionDefaultExample extends StatefulWidget {
const LoadingRegionDefaultExample({super.key});
@override
State<LoadingRegionDefaultExample> createState() => _LoadingRegionDefaultExampleState();
}
class _LoadingRegionDefaultExampleState extends State<LoadingRegionDefaultExample> {
@override
Widget build(BuildContext context) {
return LoadingRegion(
semanticLabel: 'Loading orders',
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: Theme.of(context).geometry.space(CoreSpace.space8),
children: [
Skeleton(width: 200, height: 20),
Skeleton(width: 150, height: 20),
Skeleton(width: 180, height: 20),
],
),
);
}
}
์ฌ์ฉ ์๊ธฐ (When to Use)#
์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ธ์:
- ๋ชฉ๋กยทํยท์นด๋ ๋ฌถ์์ฒ๋ผ ์ค์ผ๋ ํค ์ฌ๋ฌ ๊ฐ๊ฐ ํ ์์ญ์ ์ฑ์ธ ๋
- ํ๋ฉด์ ๋ก๋ฉ ์ค์ธ ์์ญ์ด ์ฌ๋ฟ์ด๋ผ ๋ฌด์์ด ๋ก๋ฉ ์ค์ธ์ง ๋งํด์ผ ํ ๋ (
semanticLabel: '์ฃผ๋ฌธ ๋ชฉ๋ก ๋ถ๋ฌ์ค๋ ์ค')
๋์ ๋ค๋ฅธ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ธ์:
- Skeleton ํ๋๋ง ๋จ๋ ์ผ๋ก ์ธ ๋ โ ๋จ๋ ์ค์ผ๋ ํค์ ์ค์ค๋ก ์๋ฆฝ๋๋ค
- Loading: ์๋ฆฌ ๋ชจ์์ ํ๋ด ๋ผ ํ์ ์์ด "์์ ์ค" ๋ง ๋ณด์ฌ ์ค ๋
Props / Parameters#
LoadingRegion#
| ์์ฑ | ํ์ | ๊ธฐ๋ณธ๊ฐ | ์ค๋ช |
|---|---|---|---|
child |
W |
ํ์ | ๋ก๋ฉ ์ค์ธ ์์ญ โ ๋ณดํต ๋ด์ฉ ์๋ฆฌ๋ฅผ ์ฑ์ฐ๋ ์ค์ผ๋ ํค๋ค. ์์ญ์ด ์๋ฆฌ๋ ๋์ ๋ณด์กฐ ๊ธฐ์ ์์ ์จ๊ฒจ์ง๋๋ค |
semanticLabel |
String? |
null |
์๋ฆด ๋ฌธ๊ตฌ. null ์ด๋ฉด ๋ ๋ ์์ ๋ก์ผ์ผ์ ๋ก๋ฉ ๋ฌธ๊ตฌ(์์ด "Loading", ํ๊ตญ์ด "๋ก๋ฉ ์ค")๋ฅผ ์ฝ์ต๋๋ค |
๋ณด์ด๋ ํฌ๋กฌ์ด ์์ด Style ยท Theme ์ฌ๋กฏ์ด ์์ต๋๋ค.
๋์ ์คํ (Behavior)#
-
์์ญ์ด
status์ญํ ์ ๋ผ์ด๋ธ ์์ญ ํ๋๊ฐ ๋์ดsemanticLabel(๋๋ ๋ก์ผ์ผ ๋ฌธ๊ตฌ)์ ์๋ฆฝ๋๋ค. ์ ์คํ(polite) ์๋ฆผ์ด๋ผ ์ฝ๋ ๋ฌธ์ฅ์ ๋์ง ์์ต๋๋ค. -
์์ชฝ
Skeleton์ ์์ญ ์์ ์์ผ๋ฉด ์๊ธฐ ์๋ฆผ์ ๋ด์ง ์์ต๋๋ค. ์์ญ ๋ฐ์ ์ค์ผ๋ ํค์ ์ง๊ธ์ฒ๋ผ ์ค์ค๋ก ์๋ฆฝ๋๋ค โ Flutter ์์๋ ์์ญ ์์์ ์ฐ ์ค๋ฒ๋ ์ด๋ ์์ญ ๋ฐ์ ๊ทธ๋ ค์ง๋ฏ๋ก ๊ทธ ์์ ์ค์ผ๋ ํค์ด ์ค์ค๋ก ์๋ฆฝ๋๋ค. - ์์ญ ์์ ์์ญ์ ๋ค์ ๋๋ฉด ๋ฐ๊นฅ ์์ญ๋ง ์๋ฆฝ๋๋ค.
child๋ ์์ญ์ด ์๋ฆฌ๋ ๋์ ๋ณด์กฐ ๊ธฐ์ ์์ ์จ๊ฒจ์ง๋๋ค. ๋ก๋ฉ ์ค์ ์ค์ ๋ก ์ธ ์ ์๋ ๋ด์ฉ์ ์์ญ ๋ฐ์ ๋ก๋๋ค.- ๋์ ์ค์ด๊ธฐ ์ค์ ์์๋ ์๋ฆผ์ ๊ทธ๋๋ก์ ๋๋ค(์ค์ผ๋ ํค ๋งฅ๋๋ง ๋ฉ์ถฅ๋๋ค).
์ฌ์ฉ ๊ฐ์ด๋๋ผ์ธ (Usage Guidelines)#
โ Do#
์์ญ๋ง๋ค ๋ฌด์์ด ๋ก๋ฉ ์ค์ธ์ง ๋งํ๊ธฐ
LoadingRegion(semanticLabel: '์ฃผ๋ฌธ ๋ชฉ๋ก ๋ถ๋ฌ์ค๋ ์ค', child: orderSkeletons)
LoadingRegion(semanticLabel: '์ถ์ฒ ์ํ ๋ถ๋ฌ์ค๋ ์ค', child: productSkeletons)
ํ๋ฉด์ ๋ก๋ฉ ์์ญ์ด ๋ ์ด์์ด๋ฉด ๊ธฐ๋ณธ ๋ฌธ๊ตฌ("๋ก๋ฉ ์ค")๋ง์ผ๋ก๋ ์ด๋ ์ชฝ์ธ์ง ์ ์ ์์ต๋๋ค. ๋ฌธ๊ตฌ๋ ์ฑ ์ฝํ ์ธ ๋ผ ํธ์ถ์๊ฐ ๋๊น๋๋ค.
โ Don't#
์ง๊ธ ์ธ ์ ์๋ ๋ด์ฉ์ ์์ญ ์์ ๋ฃ์ง ์๊ธฐ
// โ ํํฐ ๋ฒํผ์ด ๋ณด์กฐ ๊ธฐ์ ์์ ์ฌ๋ผ์ง๋ค
LoadingRegion(
child: Column(children: [filterBar, orderSkeletons]),
)
์์ญ์ child ์ ์ฒด๋ฅผ ๋ณด์กฐ ๊ธฐ์ ์์ ์จ๊น๋๋ค. ๋ก๋ฉ๊ณผ ์๊ด์์ด ์ธ ์ ์๋ ์ปจํธ๋กค์ ์์ญ ๋ฐ์ ๋๊ณ , ์ค์ผ๋ ํค๋ง ๊ฐ์ธ์ธ์.
์ ๊ทผ์ฑ (Accessibility)#
์ญํ #
-
Flutter:
CoUISemantics(role: status, container: true)โ ๋ผ์ด๋ธ ์์ญ ๋ ธ๋ ํ๋์ ๋ฌธ๊ตฌ๊ฐ ๋ถ์ต๋๋ค.container๋ผ ๋ผ๋ฒจ์ด ๋ถ์ ๋ถ๋ชจ ๋ ธ๋์ ์์ด์ง ์์ต๋๋ค. -
Web: ์๊ฐ์ ์ผ๋ก ์จ๊ธด(
sr-only)role="status"์์ ํ๋๊ฐ ๋ฌธ๊ตฌ๋ฅผ ํ ์คํธ๋ก ๋ด์ต๋๋ค. ๋ผ์ด๋ธ ์์ญ์ ์ด๋ฆ์ด ์๋๋ผ ๋ด์ฉ์ ์ฝ๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํค๋ณด๋#
์์ต๋๋ค. ์ด ์ปดํฌ๋ํธ๋ ์ด๋ค ํค๋ ์ฒ๋ฆฌํ์ง ์์ต๋๋ค.
์คํฌ๋ฆฐ ๋ฆฌ๋#
- ์์ญ ํ๋์ ์๋ฆผ ํ๋์
๋๋ค. ์์ชฝ ์ค์ผ๋ ํค์ ์๋ฆผ์ ๋ง๋ค์ง ์์ต๋๋ค(์ ํ๋ซํผ ๋ชจ๋
LoadingRegionScope๋ฅผ ์ฝ์ต๋๋ค). - Flutter:
child๋ExcludeSemantics์๋์ ์์ต๋๋ค. -
Web:
child๋aria-hidden="true"์ธdisplay: contents์์ ์์ ์์ต๋๋ค โ ๋ ์ด์์ ์์๋ฅผ ๋ํ์ง ์์ต๋๋ค.
ํฌ์ปค์ค ๊ด๋ฆฌ#
ํฌ์ปค์ค๋ฅผ ๊ด๋ฆฌํ์ง ์์ต๋๋ค. child ์์ ํฌ์ปค์ค ๊ฐ๋ฅํ ์์๋ ๋ณด์กฐ ๊ธฐ์ ์์ ์จ๊ฒจ์ง ์ฑ ํฌ์ปค์ค๋ฅผ ๋ฐ์ ์ ์์ผ๋ฏ๋ก, ๋ก๋ฉ ์ค์ ์ธ ์ปจํธ๋กค์ ์์ญ ๋ฐ์ ๋ก๋๋ค.
์๋ ค์ง ์ ์ฝ#
-
Web โ ์ฝ์
์๊ฐ์ ์ด๋ฏธ ๋ฌธ๊ตฌ๊ฐ ์ฐฌ ์ํ๋ก ๋ํ๋ฉ๋๋ค.
Toast์ ๊ฐ์ ๋ฐฉ์์ ๋๋ค. ์ด๋ ๊ฒ ์ฝ์ ๋ status ๋ฅผ ๋ฐ๋ก ์ฝ๋์ง๋ ์คํฌ๋ฆฐ๋ฆฌ๋๋ง๋ค ๋ค๋ฅผ ์ ์์ด ์ค๊ธฐ ํ์ธ ํญ๋ชฉ์ ๋๋ค. -
Web โ
display: contents์์์aria-hidden. ํํ ๋ธ๋ผ์ฐ์ ๋ ๋ฐ๋ฅด์ง๋ง ์ค๋๋ ๋ธ๋ผ์ฐ์ ์์๋ ๋ฌด์๋ ์ ์์ต๋๋ค. -
Web โ ๋ถ๋ชจ์ ํ์ ์ ํ์ ๊ธฐ๋ฐ ๊ฐ๊ฒฉ์
child์ ๋ฟ์ง ์์ต๋๋ค. ์์ญ์ ๋ถ๋ชจ ์์ ์จ๊ธด ์๋ด ์์์display: contents๋ํผ, ๋์ ํ์ ๋ก ๋ผ์๋๋ค.space-y-*ยทdivide-*ยท:first-child๋ ๊ทธ ๋์ ๊ฑธ๋ คchild์๋ ๊ฐ๊ฒฉ์ด ์๊ธฐ์ง ์๊ณ , ์์ญ์ด ๋น ์ง๋ฉด ๊ฐ๊ฒฉ์ด ์๊ฒจ ์ฝํ ์ธ ๊ฐ ์ ํํฉ๋๋ค. flex ยท grid ์gap์ ์ํฅ์ด ์์ต๋๋ค. - ์์ญ์ ๋ด์ฉ์ ํต์งธ๋ก ์จ๊น๋๋ค. ์ผ๋ถ๋ง ๋ก๋ฉ ์ค์ธ ์์ญ์ด๋ผ๋ฉด ๋ก๋ฉ ์ค์ธ ๋ถ๋ถ๋ง ๊ฐ์ธ์ธ์.
ํฌ๋ก์ค ํ๋ซํผ ์ฐจ์ด์ (Platform Differences)#
| ํญ๋ชฉ | Flutter | Web |
|---|---|---|
| ํด๋์ค๋ช | LoadingRegion | LoadingRegion |
| child ํ์ | Widget | Component |
| ์๋ฆผ | CoUISemantics(role: status) ๋ผ์ด๋ธ ์์ญ ๋
ธ๋ |
์จ๊ธด role="status" ์์์ ํ
์คํธ |
| ๋ด์ฉ ์จ๊น | ExcludeSemantics |
aria-hidden="true" + display: contents |
| ์ค์ผ๋ ํค ์นจ๋ฌต | LoadingRegionScope(InheritedWidget) |
LoadingRegionScope(InheritedComponent) |