순환

패널은 view(state)를 정의하고, 필요하면 initial(), on_open(state), on_action(action, state)도 정의합니다. Clink는 시작 상태를 위해 initial()을 한 번, 패널이 나타날 때마다 on_open을 부르고, 이어서 view(state)로 화면을 만듭니다. 컨트롤은 쓰고 있는 자리에 글자를 넣거나, 새 상태를 정하거나, on_action이 처리할 액션 이름을 갖습니다. 그때마다 화면이 다시 만들어집니다.

def initial():
    return {"count": 0, "step": 1}

def view(state):
    return vstack([
        text(f"{state['count']}", size=34, weight="bold", align="center"),
        segmented(["1", "5", "10"], value=str(state["step"]), action="step"),
        hstack([
            button("−", "bump", value=-1),
            button("+", "bump", value=1, style="primary"),
        ]),
        button("Type it", "type", icon="keyboard"),
    ])

def on_action(action, value, state):
    if action == "bump":
        state["count"] = state["count"] + value * state["step"]
    elif action == "step":
        state["step"] = int(value)
    elif action == "type":
        insert(str(state["count"]))
        close()
    return state
편집기의 ‘새 패널’ 버튼이 그대로 만들어 주는 출발점 패널입니다.

계산기, 스니펫 모음, 피커: 내가 만든 패널은 키보드의 패널 버튼 뒤에 나타나요.

빌더

view(state)는 이 19개의 함수가 만든 노드를 돌려줍니다. 자유롭게 중첩하세요. 스택과 그리드는 자식 목록을 받습니다.

빌더그리는 것
vstack(children, spacing=6, align="leading")자식을 아래로 쌓습니다.
hstack(children, spacing=6, align="center")자식을 가로로 늘어놓습니다.
grid(children, columns=4, spacing=6)자식을 고른 열로 흘려 배치합니다.
wrap(children, spacing=6)자식 요소를 패널 너비에 늘어놓고 넘치면 다음 줄로 넘깁니다.
scroll(children, spacing=6)자체 스크롤 영역입니다. 패널보다 긴 목록에 씁니다.
card(children, padding=10, color="")자식 요소를 한 면에 모으고 주위에 여백을 둡니다.
spacer(size=0)뒤따르는 것을 끝까지 밀어냅니다.
divider()행 사이의 가는 선입니다.
text(s, size=17, weight="regular", color="", align="leading", lines=0, mono=False)한 줄의 텍스트입니다. weight는 regular, medium, semibold, bold, heavy, light, thin을 받고, align은 leading, center, trailing을 받습니다. lines는 줄바꿈 줄 수를 제한하고, color는 색 이름이나 #RRGGBB를 받습니다.
icon(name, size=20, color="")SF Symbol을 이름으로 넣습니다.
badge(s, color="")짧은 낱말을 색을 입힌 캡슐에 담습니다.
progress(value, total=1, label="")total 중 value 만큼 채워지는 막대입니다.
button(label, action="", value=None, insert="", set=None, style="plain", icon="", enabled=True)버튼입니다. insert는 지금 쓰고 있는 곳에 그 글자를 입력하고, set은 상태에 키를 합치며, action은 on_action이 받을 이름을 지정합니다. style은 plain, primary, tinted, quiet, destructive를 받습니다.
row(title, subtitle="", detail="", icon="", action="", value=None, insert="")탭할 수 있는 행입니다. 제목, 둘째 줄, 아이콘, 오른쪽 부가 정보로 이루어집니다.
toggle(label, on=False, key="", action="")스위치입니다. key를 주면 해당 상태 키에 True 또는 False를 씁니다.
slider(value, min=0, max=100, step=1, label="", key="", action="")min에서 max 사이의 슬라이더입니다. key를 주면 위치를 해당 상태 키에 씁니다.
stepper(value, min=0, max=100, step=1, label="", key="", action="")− 와 + 가 붙은 값입니다. min에서 max 사이에서 움직입니다.
segmented(options, value=None, key="", action="")목록에서 하나를 고릅니다. key를 주면 고른 항목을 해당 상태 키에 씁니다.
field(key, placeholder="", action="", submit="")state[key]에 묶인 텍스트 상자입니다. 탭하면 키 입력이 그 키로 향하고, submit은 Return이 실행할 처리기의 이름입니다.

평범한 문자열도 노드가 놓이는 자리라면 그대로 쓸 수 있습니다. 기본 크기의 텍스트로 그려집니다.

탭에 반응하기

무언가를 계산해야 하는 컨트롤은 고정된 set 대신 action 이름을 지정합니다. 그러면 Clink가 on_action(action, state)를 호출합니다. 컨트롤이 지닌 값까지 쓰고 싶으면 on_action(action, value, state)로 받습니다. state는 평범한 딕셔너리라서 그 자리에서 고치고 아무것도 반환하지 않아도 되고, 새 딕셔너리를 반환해도 됩니다.

def initial():
    return {"items": [], "draft": ""}

def view(state):
    return vstack([
        field("draft", placeholder="Add one…", submit="add"),
        scroll([row(item, action="use", value=item) for item in state["items"]]),
    ])

def on_action(action, value, state):
    if action == "add" and value:
        state["items"].append(value)
        state["draft"] = ""
    elif action == "use":
        insert(value)
        close()
    return state
항목을 더해 두었다가 탭해서 넣는 목록입니다.

on_open(state)는 패널이 나타날 때마다 실행됩니다. 지금 쓰고 있는 글에서 초깃값을 가져오는 자리입니다.

키보드에 요청하기

on_action과 on_open에서는 반환값으로 표현할 수 없는 일을 키보드에 요청할 수 있습니다. 호출은 일단 기록해 두었다가 함수가 끝난 뒤에 적용하므로, 패널이 자기 화면을 만드는 도중에 입력란을 건드리는 일은 없습니다.

명령

  • insert()
  • backspace()
  • delete_word()
  • replace()
  • move_cursor()
  • copy()
  • close()
  • haptic()
  • toast()
def on_action(action, state):
    if action == "quote":
        word = context()["word"]
        replace(len(word), "“" + word + "”")
        haptic("light")
    return state
커서에 있는 낱말을 따옴표로 감싼 것으로 바꿉니다.

context()는 커서 주변을 읽습니다. before, selected, after, word, clipboard, locale, language, full_access, time입니다. 호출이 시작될 때 찍은 스냅샷이라 렌더링 도중에 바뀌지 않습니다.

상태

state는 평범한 딕셔너리이며 스크립트가 만들 수 있는 것은 무엇이든 담습니다. 숫자, 문자열, 불리언, None, 그리고 그것들의 리스트와 딕셔너리입니다. 호출할 때마다 되돌려 주므로, 한 번 탭에서 덧붙인 리스트는 다음 탭에도 그대로 있습니다.

def initial():
    return {"name": ""}

def view(state):
    return vstack([
        field("name", placeholder="Who?"),
        button("Greet", insert="Hi " + state["name"] + "!", style="primary"),
    ])
입력란은 지정한 상태 키에 바로 씁니다.

‘상태 기억’을 켜면 패널 내용이 다시 열어도, 키보드를 다시 켜도 남습니다. 계산기라면 꺼 두고, 목록이라면 켜 두세요.

state는 키보드가 화면에 있는 동안 살아 있고, 패널이 기억하도록 해 두었다면 더 오래 남습니다. 패널은 context()로 커서 주변 글자를 읽을 수 있을 뿐, 당신에 대한 다른 것은 읽지 못합니다.

한계

키보드가 받는 메모리는 앱의 일부에 불과하므로, 패널은 신뢰가 아니라 한계로 묶여 있습니다. 화면을 한 번 그릴 때마다 인터프리터 2,000,000단계가 주어지고, 폭주한 반복문은 키보드가 멎는 대신 화면의 오류로 끝납니다.

파일이나 저장소에서 온 패널은 저장하기 전에 검사합니다. 48,000 바이트와 1,200 줄을 넘지 않아야 하고, def view( 를 정의해야 하며, 모든 import는 샌드박스 안의 네임스페이스 중 하나를 가리켜야 합니다. 그리고 다음 조각은 그 자리에서 거부됩니다:

공유된 패널에서 거부

  • __
  • exec(
  • eval(
  • open(
  • compile(

공유 패널에서 가져올 수 있는 것

  • json
  • math
  • random
  • re
  • sys
  • time

앱 안에서 직접 쓰는 패널은 그 목록의 적용을 받지 않습니다. 그럴 때 폭주하는 반복을 멈추는 것은 단계 예산뿐이니, 빠져나갈 길을 남겨 두세요.

위치

패널마다 피커에 각자의 버튼을 주고, 하나의 패널 버튼 안에 몰아넣지 않아요. 개별 패널은 자신의 에디터에서 이 설정을 덮어쓸 수 있어요.

기본값은 그 스위치를 따르고, 단독은 항상 자기 버튼을 가지며, 그룹은 항상 안쪽에 들어갑니다.

직접 만들기

  1. Clink에서 맞춤 패널을 열고 새 패널을 누릅니다.
  2. 스크립트를 씁니다. 옆에서 진짜 패널이 미리보기로 돌아가고, 오류는 입력하는 대로 표시됩니다.
  3. 저장하고 패널을 켠 다음, 키보드의 패널 버튼을 엽니다.

공유 패널은 JSON인 .clinkpanel 파일을 만듭니다. Clink에서 다시 열면 새 id로 저장되므로, 같은 패널을 두 번 가져와도 처음 것을 덮어쓰지 않습니다.

크리에이터 ›
App Store에서 다운로드