@jogak/ui 0.1.0-alpha.3 → 0.1.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jogak/ui",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.5",
4
4
  "description": "Showcase viewer UI for Jogak — Sidebar / Preview / Controls / Actions and the JogakApp shell.",
5
5
  "keywords": [
6
6
  "jogak",
@@ -45,6 +45,7 @@
45
45
  "src/app",
46
46
  "src/components",
47
47
  "src/hooks",
48
+ "src/styles",
48
49
  "src/index.ts",
49
50
  "src/vite-env.d.ts",
50
51
  "README.md",
@@ -59,9 +60,12 @@
59
60
  "registry": "https://registry.npmjs.org/"
60
61
  },
61
62
  "dependencies": {
63
+ "clsx": "^2.1.1",
62
64
  "prism-react-renderer": "^2.4.1",
63
- "@jogak/core": "0.1.0-alpha.3",
64
- "@jogak/react": "0.1.0-alpha.3"
65
+ "tailwindcss": "^4.0.0",
66
+ "@tailwindcss/vite": "^4.0.0",
67
+ "@jogak/core": "0.1.0-alpha.5",
68
+ "@jogak/react": "0.1.0-alpha.5"
65
69
  },
66
70
  "devDependencies": {
67
71
  "@types/node": "^20.14.0",
package/src/app/App.tsx CHANGED
@@ -126,19 +126,15 @@ export function JogakApp({
126
126
  return (
127
127
  <JogakProvider registry={registry}>
128
128
  <div
129
- style={{
130
- display: 'grid',
131
- gridTemplateColumns: '260px 1fr',
132
- height: '100dvh',
133
- overflow: 'hidden',
134
- }}
129
+ data-jogak-shell
130
+ className="jogak:grid jogak:grid-cols-[260px_1fr] jogak:h-dvh jogak:overflow-hidden"
135
131
  >
136
132
  <Sidebar
137
133
  selectedEntryId={selectedEntryId}
138
134
  selectedJogakName={selectedJogakName}
139
135
  onSelect={handleSelect}
140
136
  />
141
- <main style={{ overflow: 'hidden', minHeight: 0 }}>
137
+ <main className="jogak:overflow-hidden jogak:min-h-0">
142
138
  {selectedEntryId !== null ? (
143
139
  <Preview
144
140
  entryId={selectedEntryId}
@@ -150,15 +146,7 @@ export function JogakApp({
150
146
  onResolveJogak={handleResolveJogak}
151
147
  />
152
148
  ) : (
153
- <div
154
- style={{
155
- display: 'flex',
156
- alignItems: 'center',
157
- justifyContent: 'center',
158
- height: '100%',
159
- color: '#9ca3af',
160
- }}
161
- >
149
+ <div className="jogak:flex jogak:items-center jogak:justify-center jogak:h-full jogak:text-[var(--jogak-color-fg-subtle)]">
162
150
  Select a component from the sidebar
163
151
  </div>
164
152
  )}
package/src/app/main.tsx CHANGED
@@ -2,6 +2,7 @@ import { StrictMode } from 'react'
2
2
  import { createRoot } from 'react-dom/client'
3
3
  import 'virtual:jogak'
4
4
  import { _jogakCodeTheme } from 'virtual:jogak'
5
+ import '../styles/jogak.css'
5
6
  import { JogakApp } from './App.js'
6
7
 
7
8
  const rootEl = document.getElementById('root')
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useState } from 'react'
2
2
  import type { ReactElement } from 'react'
3
+ import clsx from 'clsx'
3
4
  import { defaultActionChannel } from '@jogak/core'
4
5
  import type { ActionLog } from '@jogak/core'
5
6
 
@@ -41,75 +42,44 @@ export function Actions(): ReactElement {
41
42
  return defaultActionChannel.subscribe(setLogs)
42
43
  }, [])
43
44
 
45
+ const isEmpty = logs.length === 0
46
+
44
47
  return (
45
- <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
46
- <div
47
- style={{
48
- padding: '6px 20px',
49
- fontSize: 11,
50
- fontWeight: 700,
51
- color: '#9ca3af',
52
- textTransform: 'uppercase',
53
- letterSpacing: '0.08em',
54
- borderBottom: '1px solid #e5e7eb',
55
- background: '#f9fafb',
56
- display: 'flex',
57
- alignItems: 'center',
58
- justifyContent: 'space-between',
59
- flexShrink: 0,
60
- }}
61
- >
48
+ <div className="jogak:h-full jogak:flex jogak:flex-col">
49
+ <div className="jogak:px-5 jogak:py-1.5 jogak:text-[11px] jogak:font-bold jogak:text-[var(--jogak-color-fg-subtle)] jogak:uppercase jogak:tracking-[0.08em] jogak:border-b jogak:border-[var(--jogak-color-border)] jogak:bg-[var(--jogak-color-bg-subtle)] jogak:flex jogak:items-center jogak:justify-between jogak:shrink-0">
62
50
  <span>Actions {logs.length > 0 && `(${logs.length.toString()})`}</span>
63
51
  <button
64
52
  type="button"
65
53
  onClick={() => { defaultActionChannel.clear() }}
66
- disabled={logs.length === 0}
67
- style={{
68
- fontSize: 10,
69
- fontWeight: 600,
70
- padding: '2px 8px',
71
- border: '1px solid #d1d5db',
72
- borderRadius: 3,
73
- background: '#fff',
74
- color: logs.length === 0 ? '#9ca3af' : '#374151',
75
- cursor: logs.length === 0 ? 'default' : 'pointer',
76
- textTransform: 'none',
77
- letterSpacing: 0,
78
- }}
54
+ disabled={isEmpty}
55
+ className={clsx(
56
+ 'jogak:text-[10px] jogak:font-semibold jogak:px-2 jogak:py-0.5 jogak:border jogak:border-[var(--jogak-color-border-strong)] jogak:rounded-[var(--jogak-radius-sm)] jogak:bg-[var(--jogak-color-bg)] jogak:normal-case jogak:tracking-normal',
57
+ isEmpty
58
+ ? 'jogak:text-[var(--jogak-color-fg-subtle)] jogak:cursor-default'
59
+ : 'jogak:text-[var(--jogak-color-fg)] jogak:cursor-pointer',
60
+ )}
79
61
  >
80
62
  Clear
81
63
  </button>
82
64
  </div>
83
65
 
84
- <div style={{ flex: 1, overflow: 'auto' }}>
85
- {logs.length === 0 ? (
86
- <div
87
- style={{
88
- padding: '12px 20px',
89
- color: '#9ca3af',
90
- fontSize: 13,
91
- }}
92
- >
66
+ <div className="jogak:flex-1 jogak:overflow-auto">
67
+ {isEmpty ? (
68
+ <div className="jogak:px-5 jogak:py-3 jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[13px] jogak:leading-none">
93
69
  함수 prop이 호출되면 여기에 기록됩니다
94
70
  </div>
95
71
  ) : (
96
- <ul style={{ listStyle: 'none', margin: 0, padding: 0, fontFamily: 'monospace', fontSize: 12 }}>
72
+ <ul className="jogak:list-none jogak:m-0 jogak:p-0 jogak:font-[family-name:var(--jogak-font-mono)] jogak:text-[12px]">
97
73
  {logs.map((log) => (
98
74
  <li
99
75
  key={log.id}
100
- style={{
101
- display: 'flex',
102
- alignItems: 'baseline',
103
- gap: 10,
104
- padding: '6px 20px',
105
- borderBottom: '1px solid #f3f4f6',
106
- }}
76
+ className="jogak:flex jogak:items-baseline jogak:gap-[10px] jogak:px-5 jogak:py-1.5 jogak:border-b jogak:border-[var(--jogak-color-border-muted)]"
107
77
  >
108
- <span style={{ color: '#9ca3af', fontSize: 11, minWidth: 92 }}>
78
+ <span className="jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[11px] jogak:min-w-[92px]">
109
79
  {formatTime(log.timestamp)}
110
80
  </span>
111
- <span style={{ color: '#7c3aed', fontWeight: 600 }}>{log.name}</span>
112
- <span style={{ color: '#374151', wordBreak: 'break-all', flex: 1 }}>
81
+ <span className="jogak:text-[var(--jogak-color-violet)] jogak:font-semibold">{log.name}</span>
82
+ <span className="jogak:text-[var(--jogak-color-fg)] jogak:break-all jogak:flex-1">
113
83
  ({formatArgs(log.args)})
114
84
  </span>
115
85
  </li>
@@ -1,4 +1,5 @@
1
- import type { ReactElement, ChangeEvent, CSSProperties } from 'react'
1
+ import type { ReactElement, ChangeEvent } from 'react'
2
+ import clsx from 'clsx'
2
3
  import type { ArgType } from '@jogak/core'
3
4
 
4
5
  export interface ControlsProps {
@@ -34,6 +35,34 @@ interface ControlInputProps {
34
35
  readonly onArgChange: (key: string, value: unknown) => void
35
36
  }
36
37
 
38
+ /**
39
+ * input/select 공용 className — §6.10 의 inputClass 상수.
40
+ *
41
+ * `<select>` 에 `appearance-none` 을 일부러 적용하지 않는다 (UA dropdown 화살표 보존, §3.5).
42
+ * alpha.4 baseline 이 UA 기본 select 화살표를 캡처한 상태라 픽셀 동등을 위해 유지.
43
+ */
44
+ const inputClass =
45
+ 'jogak:px-2 jogak:py-1 ' +
46
+ 'jogak:border jogak:border-[var(--jogak-color-border-strong)] ' +
47
+ 'jogak:rounded-[var(--jogak-radius-md)] ' +
48
+ 'jogak:text-[13px] ' +
49
+ 'jogak:w-full jogak:max-w-[280px]'
50
+
51
+ /** th className 상수 — Controls table header cell. */
52
+ const thClass =
53
+ 'jogak:px-5 jogak:py-1.5 ' +
54
+ 'jogak:text-left ' +
55
+ 'jogak:text-[var(--jogak-color-fg-muted)] ' +
56
+ 'jogak:font-medium ' +
57
+ 'jogak:text-[12px] ' +
58
+ 'jogak:border-b jogak:border-[var(--jogak-color-border)]'
59
+
60
+ /** td className 상수 — Controls table body cell. */
61
+ const tdClass =
62
+ 'jogak:px-5 jogak:py-2 ' +
63
+ 'jogak:align-middle ' +
64
+ 'jogak:border-b jogak:border-[var(--jogak-color-border-muted)]'
65
+
37
66
  function ControlInput({ argKey, value, argType, onArgChange }: ControlInputProps): ReactElement {
38
67
  const kind = resolveControlKind(value, argType)
39
68
 
@@ -46,7 +75,7 @@ function ControlInput({ argKey, value, argType, onArgChange }: ControlInputProps
46
75
  onChange={(e: ChangeEvent<HTMLInputElement>) => {
47
76
  onArgChange(argKey, e.target.checked)
48
77
  }}
49
- style={{ cursor: 'pointer', width: 16, height: 16, accentColor: '#2563eb' }}
78
+ className="jogak:cursor-pointer jogak:w-4 jogak:h-4 jogak:accent-[var(--jogak-color-accent)]"
50
79
  />
51
80
  )
52
81
  case 'number':
@@ -57,7 +86,7 @@ function ControlInput({ argKey, value, argType, onArgChange }: ControlInputProps
57
86
  onChange={(e: ChangeEvent<HTMLInputElement>) => {
58
87
  onArgChange(argKey, e.target.valueAsNumber)
59
88
  }}
60
- style={inputStyle}
89
+ className={inputClass}
61
90
  />
62
91
  )
63
92
  case 'select': {
@@ -68,7 +97,7 @@ function ControlInput({ argKey, value, argType, onArgChange }: ControlInputProps
68
97
  onChange={(e: ChangeEvent<HTMLSelectElement>) => {
69
98
  onArgChange(argKey, e.target.value)
70
99
  }}
71
- style={inputStyle}
100
+ className={inputClass}
72
101
  >
73
102
  {options.map((opt) => (
74
103
  <option key={String(opt)} value={String(opt)}>
@@ -86,91 +115,44 @@ function ControlInput({ argKey, value, argType, onArgChange }: ControlInputProps
86
115
  onChange={(e: ChangeEvent<HTMLInputElement>) => {
87
116
  onArgChange(argKey, e.target.value)
88
117
  }}
89
- style={inputStyle}
118
+ className={inputClass}
90
119
  />
91
120
  )
92
121
  case 'action':
93
122
  return (
94
- <span
95
- style={{
96
- display: 'inline-block',
97
- padding: '2px 8px',
98
- fontSize: 11,
99
- fontWeight: 600,
100
- color: '#7c3aed',
101
- background: '#f5f3ff',
102
- border: '1px solid #ddd6fe',
103
- borderRadius: 4,
104
- fontFamily: 'monospace',
105
- }}
106
- >
123
+ <span className="jogak:inline-block jogak:px-2 jogak:py-0.5 jogak:text-[11px] jogak:font-semibold jogak:text-[var(--jogak-color-violet)] jogak:bg-[var(--jogak-color-violet-bg)] jogak:border jogak:border-[var(--jogak-color-violet-border)] jogak:rounded-[var(--jogak-radius-md)] jogak:font-[family-name:var(--jogak-font-mono)] jogak:leading-none">
107
124
  (action)
108
125
  </span>
109
126
  )
110
127
  case 'json':
111
128
  return (
112
- <code style={{ fontSize: 12, color: '#6b7280', fontFamily: 'monospace' }}>
129
+ <code className="jogak:text-[12px] jogak:text-[var(--jogak-color-fg-muted)] jogak:font-[family-name:var(--jogak-font-mono)]">
113
130
  {JSON.stringify(value)}
114
131
  </code>
115
132
  )
116
133
  }
117
134
  }
118
135
 
119
- const inputStyle: CSSProperties = {
120
- padding: '4px 8px',
121
- border: '1px solid #d1d5db',
122
- borderRadius: 4,
123
- fontSize: 13,
124
- width: '100%',
125
- maxWidth: 280,
126
- }
127
-
128
- const thStyle: CSSProperties = {
129
- padding: '6px 20px',
130
- textAlign: 'left',
131
- color: '#6b7280',
132
- fontWeight: 500,
133
- fontSize: 12,
134
- borderBottom: '1px solid #e5e7eb',
135
- }
136
-
137
- const tdStyle: CSSProperties = {
138
- padding: '8px 20px',
139
- verticalAlign: 'middle',
140
- borderBottom: '1px solid #f3f4f6',
141
- }
142
-
143
136
  export function Controls({ args, argTypes, onArgChange }: ControlsProps): ReactElement {
144
137
  const keys = Array.from(new Set([...Object.keys(args), ...Object.keys(argTypes)]))
145
138
  const entries = keys.map((k) => [k, args[k]] as const)
146
139
 
147
140
  return (
148
- <div style={{ borderTop: '2px solid #e5e7eb' }}>
149
- <div
150
- style={{
151
- padding: '6px 20px',
152
- fontSize: 11,
153
- fontWeight: 700,
154
- color: '#9ca3af',
155
- textTransform: 'uppercase',
156
- letterSpacing: '0.08em',
157
- borderBottom: '1px solid #e5e7eb',
158
- background: '#f9fafb',
159
- }}
160
- >
141
+ <div className="jogak:border-t-2 jogak:border-[var(--jogak-color-border)]">
142
+ <div className="jogak:px-5 jogak:py-1.5 jogak:text-[11px] jogak:font-bold jogak:text-[var(--jogak-color-fg-subtle)] jogak:uppercase jogak:tracking-[0.08em] jogak:border-b jogak:border-[var(--jogak-color-border)] jogak:bg-[var(--jogak-color-bg-subtle)]">
161
143
  Controls
162
144
  </div>
163
145
  {entries.length === 0 ? (
164
- <div style={{ padding: '12px 20px', color: '#9ca3af', fontSize: 13 }}>
146
+ <div className="jogak:px-5 jogak:py-3 jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[13px]">
165
147
  No args defined
166
148
  </div>
167
149
  ) : (
168
- <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
150
+ <table className="jogak:w-full jogak:border-collapse jogak:text-[13px]">
169
151
  <thead>
170
152
  <tr>
171
- <th style={thStyle}>Name</th>
172
- <th style={thStyle}>Control</th>
173
- <th style={thStyle}>Description</th>
153
+ <th className={thClass}>Name</th>
154
+ <th className={thClass}>Control</th>
155
+ <th className={thClass}>Description</th>
174
156
  </tr>
175
157
  </thead>
176
158
  <tbody>
@@ -179,17 +161,14 @@ export function Controls({ args, argTypes, onArgChange }: ControlsProps): ReactE
179
161
  return (
180
162
  <tr key={key}>
181
163
  <td
182
- style={{
183
- ...tdStyle,
184
- fontFamily: 'monospace',
185
- fontSize: 12,
186
- color: '#374151',
187
- whiteSpace: 'nowrap',
188
- }}
164
+ className={clsx(
165
+ tdClass,
166
+ 'jogak:font-[family-name:var(--jogak-font-mono)] jogak:text-[12px] jogak:text-[var(--jogak-color-fg)] jogak:whitespace-nowrap',
167
+ )}
189
168
  >
190
169
  {key}
191
170
  </td>
192
- <td style={tdStyle}>
171
+ <td className={tdClass}>
193
172
  <ControlInput
194
173
  argKey={key}
195
174
  value={value}
@@ -197,7 +176,7 @@ export function Controls({ args, argTypes, onArgChange }: ControlsProps): ReactE
197
176
  onArgChange={onArgChange}
198
177
  />
199
178
  </td>
200
- <td style={{ ...tdStyle, color: '#9ca3af' }}>
179
+ <td className={clsx(tdClass, 'jogak:text-[var(--jogak-color-fg-subtle)]')}>
201
180
  {argType?.description ?? ''}
202
181
  </td>
203
182
  </tr>