본문으로 건너뛰기

WindowPane

무엇이든 담아, 네 가지 운영체제 중 하나가 창을 그리는 방식으로 보여 줍니다. 제목표시줄은 끌리고 모서리는 크기가 바뀌며 버튼 세 개는 진짜 버튼이므로, 스크린샷이나 데모, 랜딩 페이지의 한 조각을 그림이 아니라 그것이 될 물건으로 보여 줄 수 있습니다.

tsx
import { WindowPane } from 'neba';

<WindowPane os="macos" title="Notes" width={520} height={320}>
  <Editor />
</WindowPane>;

진짜 창은 아닙니다. 바탕화면도, z 순서도, 페이지 바깥도 없습니다. 이 컴포넌트가 그리는 것은 창틀뿐이고, 안에 담기는 내용은 직접 넣습니다.

Props

Prop타입기본값설명
os'macos' | 'macosx' | 'windows11' | 'windows10' | 'windows8' | 'windows7' | 'windowsxp' | 'linux''macos'어느 시스템의 창인지. 컨트롤의 위치와 모양, 제목표시줄의 높이와 색, 테두리의 두께와 모서리를 정합니다. 제목표시줄이 달라진 버전마다 별도 항목입니다. XP는 Luna 블루와 그 색의 테두리, 7은 아크릴 유리, 8은 납작한 사각형, 10은 바 아래의 선, 11은 둥근 모서리, macosx는 Aqua입니다
titleReactNode제목표시줄의 이름. 창 자체의 접근성 이름이기도 합니다
iconReactNode제목 옆의 글리프, 앱의 마크
actionsReactNode제목표시줄이 함께 나르는 것. 컨트롤 옆에 놓입니다
controlsboolean | ('minimize' | 'maximize' | 'close')[]true어떤 버튼을 둘지. 순서는 배열이 아니라 시스템이 정합니다. macOS는 닫기가 앞, Windows는 뒤입니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'크롬의 스케일, 제목표시줄 높이, 버튼, 글자. 내용은 건드리지 않습니다
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'포커스 링과 accent 제목표시줄이 입는 색 계열
accentbooleanfalseWindows가 제공하는 것처럼 제목표시줄에 색 계열을 입힙니다
transparencynumber00에서 1 사이. 제목표시줄과 본문의 바탕, 테두리에만 적용되며 내용에는 적용되지 않습니다. 0보다 크면 아크릴(블러)이 함께 켜집니다
activeboolean앞에 있는 창인지. 생략하면 다른 WindowPane이 눌릴 때까지 앞에 둡니다. 뒤에 있는 창은 흐려지지 않고 강조만 잃습니다(회색 신호등, 강조색 없는 제목표시줄, 한 단계 낮은 그림자)
elevation공통0 | 1 | 2 | 32창 주위의 그림자. 0은 그림자 없음입니다
position공통'static' | 'absolute' | 'fixed''static'어떻게 배치되는지. static은 흐름 안(relative로 놓여 offset이 주변을 밀지 않습니다), absolute는 가장 가까운 positioned 조상 안, fixed는 뷰포트에 고정
draggablebooleanfalse제목표시줄을 끌 수 있게 합니다
resizablebooleanfalse가장자리와 모서리를 끌 수 있게 합니다
widthnumber | string창의 너비
heightnumber | string창의 높이. 없으면 담긴 것만큼입니다
minWidthnumber180끌어서 줄일 수 있는 최소 너비(px)
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창이 화면에 있는지. 닫히면 아무것도 렌더링하지 않습니다
defaultOpenbooleantrue제어하지 않을 때의 시작 상태
onOpenChange(open: boolean) => void닫기를 눌렀을 때
minimizedboolean제목표시줄만 남기고 말아 올렸는지. 페이지에는 창을 보낼 독이 없으므로 최소화는 이 뜻입니다
defaultMinimizedbooleanfalse제어하지 않을 때의 시작 상태
onMinimizedChange(minimized: boolean) => void최소화를 눌렀을 때
maximizedboolean담고 있는 것을 가득 채우는지. 그동안 모서리는 각져집니다
defaultMaximizedbooleanfalse제어하지 않을 때의 시작 상태
onMaximizedChange(maximized: boolean) => void최대화를 눌렀을 때, 그리고 제목표시줄을 더블클릭했을 때
scrollbooleantrue창보다 큰 내용이 스크롤될지
localestring제목표시줄 버튼이 자기 이름을 말하는 언어(BCP 47)
minimizeLabelstring최소화 버튼의 이름
maximizeLabelstring최대화 버튼의 이름
restoreLabelstring창이 최대화된 동안 그 버튼이 불리는 이름
closeLabelstring닫기 버튼의 이름
resizeLabelstring키보드로 크기를 바꾸는 모서리의 이름
renderuseRender.RenderPropdiv 대신 다른 요소로 렌더링합니다 (render={<section />})
childrenReactNode창 안에 있는 것

titleonResize를 빼면 나머지 <div> 속성은 그대로 루트에 전달됩니다. 여기서 title은 창의 이름이자 ReactNode이고, onResize는 DOM 이벤트가 아니라 픽셀 크기를 알려줍니다. 공용 축(size color elevation position)은 prop 규약에 있습니다.

예시

os

여덟 가지이며, 제목표시줄이 달라진 버전마다 별도 항목입니다.

os그리는 것
macos왼쪽에 색 있는 점 세 개, 창 전체의 가운데에 놓인 제목, 이음매 없는 한 장의 시트
macosxAqua: 낮고 줄무늬가 있는 바, 광택 있는 신호등, 굵고 양각된 제목, 각진 아래 모서리
windows11둥근 오른쪽 위 모서리에 딱 붙은 사각 버튼 셋, 바와 본문이 같은 Mica 한 장
windows10같은 셋에 각진 모서리, 더 낮은 표시줄, 그리고 그 아래 한 줄
windows8납작하고 각지며 줄은 없고, 창 전체를 두르는 색 띠
windows7Aero: 뒤를 흐리는 유리, 빛나는 제목, 더 넓은 닫기 버튼
windowsxpLuna: 파란 그러데이션 바, 같은 파란색으로 두른 테두리, 색이 든 버튼 플레이트
linuxGNOME 헤더바: 더 높고, 버튼이 원형이며, 제목이 가운데에

옛 시스템들은 페이지의 색이 아니라 자기 크롬을 칠합니다. 그래서 다크로 전환한 페이지에서도 Luna는 파랗고 Aqua는 회색입니다. Mockup의 마감재가 하는 선택과 같습니다. 하드웨어와 시스템 크롬은 테마가 아니기 때문입니다.

XP와 Aero는 헤어라인이 아니라 를 가진 둘이기도 합니다. 내용이 양옆과 아래를 두르는 시스템 자신의 재질 속에 가라앉아 있는데, 두 창을 알아보게 하는 것의 대부분이 그 띠입니다. accent는 제목표시줄과 함께 띠까지 물들이므로, 직접 고른 색의 창은 그 색으로 둘러집니다.

버튼에는 다른 회사의 마크가 없습니다. 최소화는 선, 최대화는 상자, 닫기는 ×이며, 창틀에는 넘긴 제목 말고 아무 글자도 쓰지 않습니다.

controls

true는 버튼 셋 전부, false는 없음이며, 배열은 그 안에 이름을 적은 것만입니다. 순서는 배열이 아니라 시스템이 정하므로 ['close', 'minimize']라 적어도 Windows에서는 닫기가 마지막에 옵니다.

셋 다 제어/비제어 짝을 가집니다. open, minimized, maximized에 각각 default*on*Change가 있습니다. 비제어 창을 닫으면 아무것도 렌더링하지 않습니다. 최소화는 제목표시줄만 남기고 말아 올립니다. 웹 페이지에는 창을 내려놓을 작업 표시줄이 없기 때문입니다. 최대화는 창을 담고 있는 것을 채우며, 그것은 position="absolute"에서는 가장 가까운 positioned 조상이고 fixed에서는 뷰포트입니다. 제목표시줄을 더블클릭해도 최대화됩니다.

draggable과 resizable

draggable은 창을 lefttop으로 옮기며(transform이 아니므로 끄는 동안 글자가 다시 샘플링되지 않습니다) 어디로 갔는지를 onOffsetChange로 알려줍니다. resizable은 네 가장자리와 네 모서리 전부에 핸들을 답니다. minWidthminHeight가 한계를 정하고, 움직이는 동안 onResize가 픽셀 크기와 함께 호출됩니다.

둘 다 움직일 자리가 있어야 합니다. 창에 position="absolute"와 positioned 조상을 주거나 position="fixed"를 주세요.

어느 창이 앞에 있는지

active를 넘기지 않으면 스스로 알아서 합니다. 페이지의 다른 WindowPane이 눌리거나 포커스를 가져갈 때까지 그 창이 앞에 있습니다. 창들 주변의 페이지를 누르는 것은 아무것도 바꾸지 않습니다. 문단은 바탕화면이 아닙니다.

앞에 있다는 것은 각 시스템이 그리는 방식대로 그려집니다. macOS에서는 회색이 아닌 색 있는 신호등, Windows 10에서는 강조색 제목표시줄과 강조색 테두리, GNOME에서는 색이 든 헤더바이고, 넷 모두에서 뒤에 있는 창보다 그림자가 한 단계 깊습니다. 직접 정하고 싶다면 active를 넘기세요. z 순서를 스스로 관리하는 쪽이 원하는 값입니다.

움직임

최대화, 복원, 말아 올리기는 두 기하 사이의 이동이므로 창은 뛰지 않고 지나갑니다. 움직이는 것은 left, top, width, height이며 transform은 결코 아닙니다. 그래서 오는 동안 창 안의 어떤 글자도 다시 샘플링되지 않습니다. height를 받은 적 없는 창은 말아 올리는 동안 높이를 재어 고정해 둡니다. auto는 트랜지션이 출발할 수 있는 길이가 아니기 때문입니다.

말아 올린 창은 본문을 트리에 남겨 둡니다. inert 상태로 잘려 있으며, 그것이 바로 말아 올림이 지나가는 대상입니다. 닫힌 창은 그냥 사라지는 대신 사라지기 전에 서서히 흐려집니다. 움직임을 줄여 달라고 한 사용자에게는 이 모두가 즉시 일어납니다.

accent · transparency · active

accent는 Windows가 제공하는 것처럼 제목표시줄에 color를 입히며, windows10에서는 창의 테두리까지 함께 물듭니다. 그 버전이 실제로 하는 일입니다. transparency는 크롬 너머로 페이지가 얼마나 비치는지를 0에서 1 사이로 정합니다. 제목표시줄과 본문의 바탕, 테두리에만 적용되고 그 위의 내용에는 적용되지 않으며, 0보다 크면 아크릴이 함께 켜져 뒤가 그냥 보이는 대신 흐려집니다. active={false}는 그 창을 다른 무엇보다 뒤에 고정해 둡니다.

접근성

  • 루트는 자기 제목이 이름인 role="group"이므로, 스크린 리더는 내용보다 먼저 창의 이름을 읽습니다.
  • 제목표시줄의 버튼 셋은 locale에서 이름을 받는 진짜 <button>이며, 최대화 버튼은 창이 최대화된 동안 스스로 "이전 크기로 복원"으로 이름을 바꿉니다.
  • 리사이즈 핸들 중 하나(오른쪽 아래 모서리)는 키보드로 닿을 수 있고 방향키로 크기를 바꿉니다. 나머지 일곱은 포인터를 위한 것이라 접근성 트리에서 숨겨져 있으며, 키보드 사용자는 maximize로 같은 범위를 얻습니다.
  • 끌기도 포인터를 위한 것입니다. 포인터 없이도 옮겨야 하는 창이라면 offset을 직접 넘기세요.

Released under the MIT License