본문으로 건너뛰기

PlWindowPane

여덟 가지 시스템 중 하나가 그리는 대로의 창이고, 안에는 무엇이든 넣을 수 있습니다. 진짜 창이 아니고 그런 척도 하지 않습니다. 동작하는 틀입니다.

React
tsx
import { PlWindowPane } from 'plass-ui';

<PlWindowPane title="Notes">
  <MyApp />
</PlWindowPane>;
dart
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의 자리와 모양, 표시줄의 높이, 모서리를 정합니다
titleReactNode창의 이름. 창 자체의 이름이기도 합니다
iconReactNode제목 옆의 글리프
actionsReactNode표시줄이 나르는 그 밖의 것
controlsboolean | readonly ('minimize' | 'maximize' | 'close')[]true어떤 button이 있는지. 순서는 배열이 아니라 시스템이 정합니다
accentbooleanfalseWindows가 제안하는 방식으로 표시줄을 계열 색으로 물들입니다
transparencynumber0창의 chrome 너머로 뒤가 얼마나 비치는지. 내용에는 적용되지 않습니다
activeboolean앞에 있는 창인지. 비우면 스스로 알아냅니다
position'static' | 'absolute' | 'fixed''static'창이 배치되는 방식
draggablebooleanfalse제목 표시줄을 끌 수 있게 합니다
resizablebooleanfalse변과 모서리를 끌 수 있게 합니다
widthnumber | string창의 너비
heightnumber | string창의 높이. 비우면 내용만큼입니다
minWidthnumber180끌어서 줄일 수 있는 한계
minHeightnumber아래쪽으로 같은 것. 기본은 표시줄 높이
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변이 끌리는 동안 창의 크기를 알립니다
openboolean창이 화면에 있는지. 닫으면 아무것도 그리지 않습니다
minimizedboolean제목 표시줄까지 말아 올렸는지. 보낼 곳이 없으니 자리에 그대로 남습니다
maximizedboolean담고 있는 것을 가득 채우는지
scrollbooleantrue창보다 긴 내용이 스크롤되는지
minimizeLabelstringbutton 이름을 덮어씁니다
resizeLabelstring'Resize window'키보드로 잡을 수 있는 모서리가 불리는 이름
renderReactElementdiv 대신 다른 요소를 렌더링합니다
childrenReactNode창 안에 있는 것
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'focus ring과 accent 표시줄이 입는 계열
elevation공통0 | 1 | 2 | 32창 둘레의 그림자. 창은 정의상 놓인 페이지의 일부가 아니므로 2입니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'chrome의 크기. 내용에는 손대지 않습니다
Prop타입기본값설명
osPlWindowOsPlWindowOs.macos누구의 창인지. button의 자리와 모양, 표시줄의 높이, 모서리를 정합니다
titleWidget?창의 이름. 창 자체의 이름이기도 합니다
iconWidget?제목 옆의 글리프
actionsWidget?표시줄이 나르는 그 밖의 것
controlsSet<PlWindowControl>all three어떤 button이 있는지. React의 boolean | 배열 대신 Set입니다 — 순서는 어차피 시스템이 정하니까요
accentboolfalseWindows가 제안하는 방식으로 표시줄을 계열 색으로 물들입니다
transparencydouble0창의 chrome 너머로 뒤가 얼마나 비치는지. 내용에는 적용되지 않습니다
activebooltrue앞에 있는 창인지. React와 달리 스스로 알아내지 않습니다 — 귀 기울일 문서가 없습니다
draggableboolfalse제목 표시줄을 끌 수 있게 합니다
resizableboolfalse변과 모서리를 끌 수 있게 합니다
widthdouble?창의 너비
heightdouble?창의 높이. 비우면 내용만큼입니다
minWidthdouble180끌어서 줄일 수 있는 한계
minHeightdouble?아래쪽으로 같은 것. 기본은 표시줄 높이
offsetOffsetOffset.zero배치된 자리에서 얼마나 끌려 왔는지. 앞쪽 변을 끌면 크기와 함께 자리도 바뀝니다
onOffsetChangedValueChanged<Offset>?끌리는 동안 부릅니다
onResizeValueChanged<Size>?변이 끌리는 동안 창의 크기를 알립니다
openbooltrue창이 화면에 있는지. 닫으면 아무것도 그리지 않습니다
onOpenChangedValueChanged<bool>?close를 누르면 부릅니다
minimizedboolfalse제목 표시줄까지 말아 올렸는지. 보낼 곳이 없으니 자리에 그대로 남습니다
onMinimizedChangedValueChanged<bool>?minimize를 누르면 부릅니다
maximizedboolfalse담고 있는 것을 가득 채우는지
onMaximizedChangedValueChanged<bool>?maximize를 누르면 부릅니다
minimizeLabelString?button 이름을 덮어씁니다
resizeLabelString?'Resize window'키보드로 잡을 수 있는 모서리가 불리는 이름
childWidget?창 안에 있는 것
color공통PlassColorPlassColor.primaryfocus ring과 accent 표시줄이 입는 계열
elevation공통int2창 둘레의 그림자. 창은 정의상 놓인 페이지의 일부가 아니므로 2입니다
size공통PlassSizePlassSize.mdchrome의 크기. 내용에는 손대지 않습니다

minimize는 창을 어디로 보내지 않고 제목 표시줄까지 말아 올립니다. 페이지에는 보낼 곳이 없기 때문입니다. maximize는 창을 담고 있는 것을 가득 채웁니다.

size는 chrome만 키웁니다. 표시줄, button, 제목입니다. 창의 내용은 caller의 것이고 자기 척도로 배치됩니다. 제목 표시줄이 문서를 따라 커지지 않는 진짜 바탕화면에서와 똑같습니다. PlBox, PlMockup에 이어 사다리가 컨트롤 높이가 아닌 것을 뜻하는 세 번째 컴포넌트입니다.

Examples

os

React

버전은 제목 표시줄 이 바뀐 곳마다 따로 들어갑니다. Windows가 다섯이고 나머지가 하나둘인 이유입니다. XP는 표시줄을 Luna 파랑으로 칠하고 창을 그 파랑으로 둘렀고, 7은 그것을 유리로 만들었고, 8은 둘 다 버리고 각진 흰 판으로 갔고, 10은 표시줄과 본문 사이에 선을 그었고, 11은 모서리를 둥글리고 둘을 다시 한 장으로 만들었습니다. macosx는 Aqua이고, 그것을 대신한 평평한 macos와 나란히 있습니다.

창에 어떤 button이 있는지는 caller가 정하지만, 어떤 순서로 놓이는지는 시스템이 정합니다. macOS는 close를 맨 앞에, Windows는 맨 뒤에 둡니다. caller가 외우고 있을 일이 아닙니다.

여기 있는 어느 것도 그 시스템들의 복제가 아닙니다. 그려지는 것은 그 시스템이 쓰던 비율의 표시줄과 테두리와 button 셋뿐이고, 남의 마크나 워드마크나 아이콘은 하나도 없습니다.

accent와 active

React

앞에 있는 창 뒤의 창은 모양을 지키고 강조를 잃습니다. 색이 빠지고 그림자가 한 단 내려가고 제목이 회색이 됩니다. opacity는 쓰지 않습니다. 그러면 chrome과 함께 내용까지 흐려집니다.

React에서는 active를 비워 두면 창이 스스로 알아냅니다. 페이지의 다른 창이 눌리거나 focus를 가져갈 때까지 앞에 있습니다. 창들 주변 의 클릭은 아무것도 바꾸지 않습니다. 문단은 바탕화면이 아니기 때문입니다. Flutter에서는 그냥 값입니다. 귀 기울일 문서가 없고, 트리를 가로질러 다른 창을 찾는 위젯은 바탕화면을 만들어 내는 셈입니다.

transparency

React

제목 표시줄과 본문의 바탕, 테두리에 적용됩니다. 그 위의 내용에는 절대 적용되지 않고, 내용은 그대로 읽힙니다. React에서는 0을 넘기면 blur도 켜지므로 아래 페이지가 그저 비치는 것이 아니라 흐려집니다.

draggable와 resizable

제목 표시줄이 끌리고 여덟 모서리와 변이 크기를 바꿉니다. 둘 다 기본은 꺼짐입니다. 페이지 속의 창은 대개 창의 그림이고, 스치기만 해도 움직이는 틀은 놀랄 일입니다.

크기는 minWidthminHeight에서 멈추고, 멈춘 크기를 onResize가 알립니다. 왼쪽이나 위쪽 변을 끌면 창이 크기와 함께 자리도 옮기므로 그동안 onOffsetChange도 함께 부릅니다.

Accessibility

  • 창은 제목에서 이름을 가져오는 이름 붙은 group입니다. React에서는 aria-labelledby가 붙은 role="group"이고, Flutter에서는 explicitChildNodes를 켠 semantics container입니다. 제목과 button과 내용의 모든 낱말이 하나의 긴 이름으로 합쳐지는 것을 막는 것이 그것입니다.
  • button 셋은 진짜 button이고 자기가 하는 일을 말합니다. 창이 가득 찬 뒤 maximizeRestore가 됩니다. 모든 시스템이 그렇게 부릅니다.
  • 여덟 개의 크기 손잡이 중 하나만 포인터 없이 닿습니다. 두 축을 한 번에 바꾸는 모서리입니다. 창마다 여덟 개의 tab 정거장은 키보드로 읽는 사람에게 나머지 일곱 방향의 값어치보다 비쌉니다. 화살표 키가 그 모서리를 움직입니다. 나머지 일곱은 이름 없이 남기는 대신 접근성 트리에서 감춥니다.
  • 말아 올린 창의 내용은 없어지는 것이 아니라 손이 닿지 않게 됩니다. 트리에는 남되 inert로 표시되므로, 접힌 표시줄 아래의 어떤 것에도 tab으로 들어갈 수 없습니다.

Released under the MIT License