PlWindowPane
여덟 가지 시스템 중 하나가 그리는 대로의 창이고, 안에는 무엇이든 넣을 수 있습니다. 진짜 창이 아니고 그런 척도 하지 않습니다. 동작하는 틀입니다.
import { PlWindowPane } from 'plass-ui';
<PlWindowPane title="Notes">
<MyApp />
</PlWindowPane>;import 'package:plass_ui/plass_ui.dart';
PlWindowPane(title: const Text('Notes'), child: MyApp());바탕화면도, z 순서도, dock도 없습니다. 있는 것은 끌리는 제목 표시줄과 크기가 바뀌는 모서리, 그리고 진짜 이름이 붙은 진짜 button 셋입니다. 그래서 앱의 스크린샷이나 기능 시연, 랜딩 페이지의 한 조각을 그것의 그림이 아니라 그것이 될 물건으로 보여 줄 수 있습니다.
여기서 변형되는 것은 아무것도 없습니다. 끌린 창은 위치가 움직이고 크기를 바꾼 창은 너비와 높이가 바뀝니다. 그래서 두 동작 내내 안의 글자가 정수 픽셀에 남습니다. 축소·확대했다면 끄는 동안 창 안의 모든 글자가 다시 샘플링됐을 텐데, 표면을 변형하지 말라는 집안 규칙이 막으려는 것이 바로 그것입니다.
Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| os | 'macos' | 'macosx' | 'windows11' | 'windows10' | 'windows8' | 'windows7' | 'windowsxp' | 'linux' | 'macos' | 누구의 창인지. button의 자리와 모양, 표시줄의 높이, 모서리를 정합니다 |
| title | ReactNode | — | 창의 이름. 창 자체의 이름이기도 합니다 |
| icon | ReactNode | — | 제목 옆의 글리프 |
| actions | ReactNode | — | 표시줄이 나르는 그 밖의 것 |
| controls | boolean | readonly ('minimize' | 'maximize' | 'close')[] | true | 어떤 button이 있는지. 순서는 배열이 아니라 시스템이 정합니다 |
| accent | boolean | false | Windows가 제안하는 방식으로 표시줄을 계열 색으로 물들입니다 |
| transparency | number | 0 | 창의 chrome 너머로 뒤가 얼마나 비치는지. 내용에는 적용되지 않습니다 |
| active | boolean | — | 앞에 있는 창인지. 비우면 스스로 알아냅니다 |
| position | 'static' | 'absolute' | 'fixed' | 'static' | 창이 배치되는 방식 |
| draggable | boolean | false | 제목 표시줄을 끌 수 있게 합니다 |
| resizable | boolean | false | 변과 모서리를 끌 수 있게 합니다 |
| width | number | string | — | 창의 너비 |
| height | number | string | — | 창의 높이. 비우면 내용만큼입니다 |
| minWidth | number | 180 | 끌어서 줄일 수 있는 한계 |
| minHeight | number | — | 아래쪽으로 같은 것. 기본은 표시줄 높이 |
| offset | { x: number; y: number } | — | 배치된 자리에서 얼마나 끌려 왔는지 |
| defaultOffset | { x: number; y: number } | { x: 0, y: 0 } | 제어되지 않는 창이 시작하는 자리 |
| onOffsetChange | (offset: { x: number; y: number }) => void | — | 끌리는 동안 부릅니다 |
| onResize | (size: { width: number; height: number }) => void | — | 변이 끌리는 동안 창의 크기를 알립니다 |
| open | boolean | — | 창이 화면에 있는지. 닫으면 아무것도 그리지 않습니다 |
| minimized | boolean | — | 제목 표시줄까지 말아 올렸는지. 보낼 곳이 없으니 자리에 그대로 남습니다 |
| maximized | boolean | — | 담고 있는 것을 가득 채우는지 |
| scroll | boolean | true | 창보다 긴 내용이 스크롤되는지 |
| minimizeLabel | string | — | button 이름을 덮어씁니다 |
| resizeLabel | string | 'Resize window' | 키보드로 잡을 수 있는 모서리가 불리는 이름 |
| render | ReactElement | — | div 대신 다른 요소를 렌더링합니다 |
| children | ReactNode | — | 창 안에 있는 것 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | focus ring과 accent 표시줄이 입는 계열 |
| elevation공통 | 0 | 1 | 2 | 3 | 2 | 창 둘레의 그림자. 창은 정의상 놓인 페이지의 일부가 아니므로 2입니다 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | chrome의 크기. 내용에는 손대지 않습니다 |
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| os | PlWindowOs | PlWindowOs.macos | 누구의 창인지. button의 자리와 모양, 표시줄의 높이, 모서리를 정합니다 |
| title | Widget? | — | 창의 이름. 창 자체의 이름이기도 합니다 |
| icon | Widget? | — | 제목 옆의 글리프 |
| actions | Widget? | — | 표시줄이 나르는 그 밖의 것 |
| controls | Set<PlWindowControl> | all three | 어떤 button이 있는지. React의 boolean | 배열 대신 Set입니다 — 순서는 어차피 시스템이 정하니까요 |
| accent | bool | false | Windows가 제안하는 방식으로 표시줄을 계열 색으로 물들입니다 |
| transparency | double | 0 | 창의 chrome 너머로 뒤가 얼마나 비치는지. 내용에는 적용되지 않습니다 |
| active | bool | true | 앞에 있는 창인지. React와 달리 스스로 알아내지 않습니다 — 귀 기울일 문서가 없습니다 |
| draggable | bool | false | 제목 표시줄을 끌 수 있게 합니다 |
| resizable | bool | false | 변과 모서리를 끌 수 있게 합니다 |
| width | double? | — | 창의 너비 |
| height | double? | — | 창의 높이. 비우면 내용만큼입니다 |
| minWidth | double | 180 | 끌어서 줄일 수 있는 한계 |
| minHeight | double? | — | 아래쪽으로 같은 것. 기본은 표시줄 높이 |
| offset | Offset | Offset.zero | 배치된 자리에서 얼마나 끌려 왔는지. 앞쪽 변을 끌면 크기와 함께 자리도 바뀝니다 |
| onOffsetChanged | ValueChanged<Offset>? | — | 끌리는 동안 부릅니다 |
| onResize | ValueChanged<Size>? | — | 변이 끌리는 동안 창의 크기를 알립니다 |
| open | bool | true | 창이 화면에 있는지. 닫으면 아무것도 그리지 않습니다 |
| onOpenChanged | ValueChanged<bool>? | — | close를 누르면 부릅니다 |
| minimized | bool | false | 제목 표시줄까지 말아 올렸는지. 보낼 곳이 없으니 자리에 그대로 남습니다 |
| onMinimizedChanged | ValueChanged<bool>? | — | minimize를 누르면 부릅니다 |
| maximized | bool | false | 담고 있는 것을 가득 채우는지 |
| onMaximizedChanged | ValueChanged<bool>? | — | maximize를 누르면 부릅니다 |
| minimizeLabel | String? | — | button 이름을 덮어씁니다 |
| resizeLabel | String? | 'Resize window' | 키보드로 잡을 수 있는 모서리가 불리는 이름 |
| child | Widget? | — | 창 안에 있는 것 |
| color공통 | PlassColor | PlassColor.primary | focus ring과 accent 표시줄이 입는 계열 |
| elevation공통 | int | 2 | 창 둘레의 그림자. 창은 정의상 놓인 페이지의 일부가 아니므로 2입니다 |
| size공통 | PlassSize | PlassSize.md | chrome의 크기. 내용에는 손대지 않습니다 |
minimize는 창을 어디로 보내지 않고 제목 표시줄까지 말아 올립니다. 페이지에는 보낼 곳이 없기 때문입니다. maximize는 창을 담고 있는 것을 가득 채웁니다.
size는 chrome만 키웁니다. 표시줄, button, 제목입니다. 창의 내용은 caller의 것이고 자기 척도로 배치됩니다. 제목 표시줄이 문서를 따라 커지지 않는 진짜 바탕화면에서와 똑같습니다. PlBox, PlMockup에 이어 사다리가 컨트롤 높이가 아닌 것을 뜻하는 세 번째 컴포넌트입니다.
Examples
os
버전은 제목 표시줄 이 바뀐 곳마다 따로 들어갑니다. Windows가 다섯이고 나머지가 하나둘인 이유입니다. XP는 표시줄을 Luna 파랑으로 칠하고 창을 그 파랑으로 둘렀고, 7은 그것을 유리로 만들었고, 8은 둘 다 버리고 각진 흰 판으로 갔고, 10은 표시줄과 본문 사이에 선을 그었고, 11은 모서리를 둥글리고 둘을 다시 한 장으로 만들었습니다. macosx는 Aqua이고, 그것을 대신한 평평한 macos와 나란히 있습니다.
창에 어떤 button이 있는지는 caller가 정하지만, 어떤 순서로 놓이는지는 시스템이 정합니다. macOS는 close를 맨 앞에, Windows는 맨 뒤에 둡니다. caller가 외우고 있을 일이 아닙니다.
여기 있는 어느 것도 그 시스템들의 복제가 아닙니다. 그려지는 것은 그 시스템이 쓰던 비율의 표시줄과 테두리와 button 셋뿐이고, 남의 마크나 워드마크나 아이콘은 하나도 없습니다.
accent와 active
앞에 있는 창 뒤의 창은 모양을 지키고 강조를 잃습니다. 색이 빠지고 그림자가 한 단 내려가고 제목이 회색이 됩니다. opacity는 쓰지 않습니다. 그러면 chrome과 함께 내용까지 흐려집니다.
React에서는 active를 비워 두면 창이 스스로 알아냅니다. 페이지의 다른 창이 눌리거나 focus를 가져갈 때까지 앞에 있습니다. 창들 주변 의 클릭은 아무것도 바꾸지 않습니다. 문단은 바탕화면이 아니기 때문입니다. Flutter에서는 그냥 값입니다. 귀 기울일 문서가 없고, 트리를 가로질러 다른 창을 찾는 위젯은 바탕화면을 만들어 내는 셈입니다.
transparency
제목 표시줄과 본문의 바탕, 테두리에 적용됩니다. 그 위의 내용에는 절대 적용되지 않고, 내용은 그대로 읽힙니다. React에서는 0을 넘기면 blur도 켜지므로 아래 페이지가 그저 비치는 것이 아니라 흐려집니다.
draggable와 resizable
제목 표시줄이 끌리고 여덟 모서리와 변이 크기를 바꿉니다. 둘 다 기본은 꺼짐입니다. 페이지 속의 창은 대개 창의 그림이고, 스치기만 해도 움직이는 틀은 놀랄 일입니다.
크기는 minWidth와 minHeight에서 멈추고, 멈춘 크기를 onResize가 알립니다. 왼쪽이나 위쪽 변을 끌면 창이 크기와 함께 자리도 옮기므로 그동안 onOffsetChange도 함께 부릅니다.
Accessibility
- 창은 제목에서 이름을 가져오는 이름 붙은 group입니다. React에서는
aria-labelledby가 붙은role="group"이고, Flutter에서는explicitChildNodes를 켠 semantics container입니다. 제목과 button과 내용의 모든 낱말이 하나의 긴 이름으로 합쳐지는 것을 막는 것이 그것입니다. - button 셋은 진짜 button이고 자기가 하는 일을 말합니다. 창이 가득 찬 뒤
maximize는 Restore가 됩니다. 모든 시스템이 그렇게 부릅니다. - 여덟 개의 크기 손잡이 중 하나만 포인터 없이 닿습니다. 두 축을 한 번에 바꾸는 모서리입니다. 창마다 여덟 개의 tab 정거장은 키보드로 읽는 사람에게 나머지 일곱 방향의 값어치보다 비쌉니다. 화살표 키가 그 모서리를 움직입니다. 나머지 일곱은 이름 없이 남기는 대신 접근성 트리에서 감춥니다.
- 말아 올린 창의 내용은 없어지는 것이 아니라 손이 닿지 않게 됩니다. 트리에는 남되 inert로 표시되므로, 접힌 표시줄 아래의 어떤 것에도 tab으로 들어갈 수 없습니다.