@openchamber/sdk 2.1.1 → 2.3.0

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/dist/ui/style.js CHANGED
@@ -48,6 +48,9 @@ const errorText = v('error-text', 'inherit');
48
48
  const font = v('font-sans', 'inherit');
49
49
  const mono = v('font-mono', 'monospace');
50
50
  const radius = v('radius', '9px');
51
+ /** The app's controls round a step below the host radius: 7px against its 9px. */
52
+ const controlRadius = `calc(${radius} - 2px)`;
53
+ const smallRadius = `calc(${radius} - 4px)`;
51
54
  const mix = (color, pct, base = 'transparent') => (`color-mix(in srgb, ${color} ${pct}%, ${base})`);
52
55
  const focusRing = `box-shadow: 0 0 0 2px ${focus};`;
53
56
  const tone = (name) => {
@@ -55,23 +58,125 @@ const tone = (name) => {
55
58
  return `
56
59
  .oc-sdk[data-tone="${name}"], .oc-sdk [data-tone="${name}"] { --oc-sdk-tone: ${color}; --oc-sdk-tone-text: ${v(`${name}-text`, 'inherit')}; }`;
57
60
  };
58
- export const UI_CSS = `
59
- ${GUEST_SCROLLBAR_CSS}
60
- .oc-sdk { box-sizing: border-box; color: ${fg}; font-family: ${font}; font-size: 0.875rem; line-height: 1.45; }
61
+ /**
62
+ * Geometry: display, sizes, spacing, type scale, positioning. It ships inside
63
+ * each extension's bundle and changes only when the author rebuilds, so a
64
+ * layout built around these sizes never shifts under an installed extension.
65
+ */
66
+ const UI_SIZE_CSS = `
67
+ .oc-sdk { box-sizing: border-box; font-size: 0.875rem; line-height: 1.45; }
61
68
  .oc-sdk *, .oc-sdk *::before, .oc-sdk *::after { box-sizing: border-box; }
62
69
  /* :where() keeps the reset at zero specificity so every primitive class below overrides it. */
63
70
  :where(.oc-sdk) :where(button, input, textarea), :where(button.oc-sdk, input.oc-sdk, textarea.oc-sdk) { font: inherit; color: inherit; margin: 0; }
64
71
  :where(.oc-sdk) :where(button), :where(button.oc-sdk) { cursor: pointer; background: none; border: 0; padding: 0; }
65
72
  .oc-sdk button:disabled, button.oc-sdk:disabled, .oc-sdk[aria-disabled="true"], .oc-sdk [aria-disabled="true"] { opacity: .5; pointer-events: none; }
73
+
74
+ .oc-sdk-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 32px; padding: 0 12px; border: 1px solid transparent; font-size: 0.875rem; font-weight: 500; line-height: 1; white-space: nowrap; }
75
+ .oc-sdk-btn[data-size="sm"] { gap: 6px; height: 28px; padding: 0 10px; font-size: 0.8125rem; }
76
+ .oc-sdk-btn[data-size="xs"] { gap: 4px; height: 24px; padding: 0 8px; font-size: 0.75rem; }
77
+ .oc-sdk-btn[data-loading="true"] { opacity: .5; pointer-events: none; }
78
+ .oc-sdk-btn > .oc-sdk-spinner-ring { width: 14px; height: 14px; }
79
+
80
+ .oc-sdk-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
81
+ .oc-sdk-field-label { font-size: 0.8125rem; font-weight: 500; }
82
+ .oc-sdk-field-note { font-size: 0.75rem; }
83
+ .oc-sdk-input { display: block; width: 100%; min-width: 0; height: 32px; padding: 0 10px; border: 0; font-size: 0.875rem; line-height: 1.45; appearance: none; }
84
+ textarea.oc-sdk-input { height: auto; padding: 8px 10px; resize: vertical; }
85
+
86
+ .oc-sdk-search { position: relative; min-width: 0; }
87
+ .oc-sdk-search .oc-sdk-input { padding-left: 34px; padding-right: 34px; }
88
+ .oc-sdk-search-icon { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); pointer-events: none; }
89
+ .oc-sdk-search-clear { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); display: none; align-items: center; justify-content: center; width: 24px; height: 24px; }
90
+ .oc-sdk-search[data-active="true"] .oc-sdk-search-clear { display: inline-flex; }
91
+
92
+ .oc-sdk-select { position: relative; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
93
+ .oc-sdk-trigger { display: inline-flex; align-items: center; gap: 6px; width: 100%; min-width: 0; height: 28px; padding: 0 10px; border: 1px solid transparent; font-size: 0.8125rem; text-align: left; }
94
+ .oc-sdk-trigger-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
95
+ .oc-sdk-trigger-chevron { flex: 0 0 auto; }
96
+ .oc-sdk-popup { position: fixed; z-index: 50; display: flex; flex-direction: column; gap: 2px; min-width: 160px; max-width: calc(100vw - 16px); max-height: min(320px, calc(100vh - 16px)); overflow: auto; padding: 4px; border: 1px solid transparent; }
97
+ .oc-sdk-popup-search { flex: 0 0 auto; padding: 2px 2px 4px; }
98
+ .oc-sdk-popup-search .oc-sdk-input { height: 28px; font-size: 0.8125rem; }
99
+ .oc-sdk-option { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 8px; font-size: 0.8125rem; text-align: left; }
100
+ .oc-sdk-option-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
101
+ .oc-sdk-option-hint { flex: 0 0 auto; font-size: 0.75rem; }
102
+ .oc-sdk-option-check { flex: 0 0 auto; display: inline-flex; width: 14px; visibility: hidden; }
103
+ .oc-sdk-option[aria-selected="true"] > .oc-sdk-option-check { visibility: visible; }
104
+ .oc-sdk-popup-empty { padding: 8px; font-size: 0.8125rem; }
105
+
106
+ .oc-sdk-check { display: inline-flex; align-items: flex-start; gap: 8px; width: 100%; text-align: left; }
107
+ .oc-sdk-check-box { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-top: 3px; border: 1px solid transparent; }
108
+ .oc-sdk-check-box > svg { display: none; }
109
+ .oc-sdk-check[aria-checked="true"] .oc-sdk-check-box > svg { display: block; }
110
+ .oc-sdk-check-thumb { flex: 0 0 auto; position: relative; width: 36px; height: 20px; }
111
+ .oc-sdk-check-thumb::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; }
112
+ .oc-sdk-check-text { display: flex; flex-direction: column; min-width: 0; }
113
+ .oc-sdk-check-label { font-size: 0.875rem; }
114
+ .oc-sdk-check-desc { font-size: 0.75rem; }
115
+
116
+ .oc-sdk-tabs { display: inline-flex; gap: 2px; padding: 2px; max-width: 100%; overflow: auto; }
117
+ .oc-sdk-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px; border: 1px solid transparent; font-size: 0.8125rem; font-weight: 500; white-space: nowrap; }
118
+ .oc-sdk-tab-count { font-size: 0.75rem; font-variant-numeric: tabular-nums; }
119
+
120
+ .oc-sdk-badge { display: inline-flex; align-items: center; padding: 1px 6px; font-size: 11px; font-weight: 500; line-height: 16px; white-space: nowrap; }
121
+
122
+ .oc-sdk-list { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
123
+ .oc-sdk-row { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 8px; text-align: left; }
124
+ .oc-sdk-row-lead { flex: 0 0 auto; width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; }
125
+ .oc-sdk-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
126
+ .oc-sdk-row-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
127
+ .oc-sdk-row-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; }
128
+ .oc-sdk-row-meta { flex: 0 0 auto; font-size: 0.75rem; font-variant-numeric: tabular-nums; }
129
+ .oc-sdk-list-empty { padding: 16px 8px; text-align: center; font-size: 0.8125rem; }
130
+
131
+ .oc-sdk-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 40px 16px; text-align: center; }
132
+ .oc-sdk-empty-title { margin: 0; font-size: 0.8125rem; font-weight: 600; }
133
+ .oc-sdk-empty-body { margin: 0; max-width: 32rem; font-size: 0.8125rem; }
134
+ .oc-sdk-empty-action { margin-top: 12px; }
135
+
136
+ @keyframes oc-sdk-spin { to { transform: rotate(360deg); } }
137
+ .oc-sdk-spinner { display: inline-flex; align-items: center; gap: 8px; font-size: 0.8125rem; }
138
+ .oc-sdk-spinner-ring { width: 16px; height: 16px; border: 2px solid transparent; animation: oc-sdk-spin .8s linear infinite; }
139
+ .oc-sdk-spinner[data-size="sm"] .oc-sdk-spinner-ring { width: 12px; height: 12px; }
140
+
141
+ .oc-sdk-banner { display: flex; align-items: flex-start; gap: 12px; padding: 8px 12px; border: 1px solid transparent; }
142
+ .oc-sdk-banner-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
143
+ .oc-sdk-banner-title { font-size: 0.8125rem; font-weight: 500; }
144
+ .oc-sdk-banner-body { font-size: 0.8125rem; }
145
+ .oc-sdk-banner-action { flex: 0 0 auto; }
146
+
147
+ .oc-sdk-separator { display: flex; align-items: center; gap: 8px; width: 100%; margin: 8px 0; font-size: 0.75rem; }
148
+ .oc-sdk-separator::before, .oc-sdk-separator::after { content: ""; flex: 1 1 auto; height: 1px; }
149
+ .oc-sdk-separator[data-labeled="false"]::after { display: none; }
150
+ .oc-sdk-popup > .oc-sdk-separator { margin: 4px 0; }
151
+
152
+ .oc-sdk-progress { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
153
+ .oc-sdk-progress-label { display: flex; justify-content: space-between; font-size: 0.75rem; font-variant-numeric: tabular-nums; }
154
+ .oc-sdk-progress-track { height: 6px; overflow: hidden; }
155
+ .oc-sdk-progress-fill { height: 100%; transform-origin: left; transition: transform 200ms ease-out; }
156
+
157
+ .oc-sdk-menu { position: relative; display: inline-flex; }
158
+
159
+ .oc-sdk-text { white-space: pre-wrap; overflow-wrap: anywhere; }
160
+ .oc-sdk-text img { display: block; max-width: 100%; margin: 8px 0; }
161
+ `;
162
+ /**
163
+ * Appearance: colours, fonts, borders, corner radii, shadows, and the hover,
164
+ * pressed, selected and focus states. The kit carries it for previews outside
165
+ * the host, and the server appends the running app's copy to every served
166
+ * extension document, after the kit's own style element, so installed bundles
167
+ * follow the app's look without a rebuild. Selectors here keep the specificity
168
+ * of the rules they override in older bundles.
169
+ */
170
+ export const GUEST_UI_LOOK_CSS = `
171
+ .oc-sdk { color: ${fg}; font-family: ${font}; }
66
172
  .oc-sdk :focus-visible { outline: none; ${focusRing} }
67
173
  .oc-sdk-mono { font-family: ${mono}; }
68
174
  .oc-sdk-muted { color: ${muted}; }
69
175
  ${tone('success')}${tone('warning')}${tone('error')}${tone('info')}
70
176
  .oc-sdk[data-tone="primary"], .oc-sdk [data-tone="primary"] { --oc-sdk-tone: ${primary}; --oc-sdk-tone-text: ${primaryText}; }
71
177
 
72
- .oc-sdk-btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 36px; padding: 0 14px; border: 1px solid transparent; border-radius: ${radius}; font-size: 0.875rem; font-weight: 500; line-height: 1; white-space: nowrap; transition: background 150ms ease-out, color 150ms ease-out; }
73
- .oc-sdk-btn[data-size="sm"] { height: 32px; padding: 0 10px; font-size: 0.8125rem; }
74
- .oc-sdk-btn[data-size="xs"] { height: 24px; padding: 0 8px; font-size: 0.75rem; border-radius: 6px; }
178
+ .oc-sdk-btn { border-radius: ${controlRadius}; transition: background 150ms ease-out, color 150ms ease-out; }
179
+ .oc-sdk-btn[data-size="xs"] { border-radius: ${smallRadius}; }
75
180
  .oc-sdk-btn[data-variant="default"] { color: ${primaryText}; background: ${mix(primary, 10, bg)}; border-color: ${mix(primary, 12)}; }
76
181
  .oc-sdk-btn[data-variant="default"]:hover { background: ${mix(primary, 16, bg)}; }
77
182
  .oc-sdk-btn[data-variant="default"]:active { background: ${mix(primary, 22, bg)}; }
@@ -87,15 +192,10 @@ ${tone('success')}${tone('warning')}${tone('error')}${tone('info')}
87
192
  .oc-sdk-btn[data-variant="destructive"] { --oc-sdk-tone: ${v('status-error', 'red')}; color: ${errorText}; background: ${mix('var(--oc-sdk-tone)', 7, bg)}; border-color: ${mix('var(--oc-sdk-tone)', 12)}; }
88
193
  .oc-sdk-btn[data-variant="destructive"]:hover { background: ${mix('var(--oc-sdk-tone)', 9, bg)}; }
89
194
  .oc-sdk-btn[data-variant="destructive"]:active { background: ${mix('var(--oc-sdk-tone)', 11, bg)}; }
90
- .oc-sdk-btn[data-loading="true"] { opacity: .5; pointer-events: none; }
91
- .oc-sdk-btn > .oc-sdk-spinner-ring { width: 14px; height: 14px; }
92
195
 
93
- .oc-sdk-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
94
- .oc-sdk-field-label { font-size: 0.8125rem; font-weight: 500; }
95
- .oc-sdk-field-note { font-size: 0.75rem; color: ${muted}; }
196
+ .oc-sdk-field-note { color: ${muted}; }
96
197
  .oc-sdk-field[data-invalid="true"] .oc-sdk-field-note { color: ${errorText}; }
97
- .oc-sdk-input { display: block; width: 100%; min-width: 0; height: 36px; padding: 0 12px; border: 0; border-radius: ${radius}; background: ${elevated}; color: ${elevatedFg}; font-size: 0.875rem; line-height: 1.45; appearance: none; box-shadow: inset 0 0 0 1px ${mix(border, 60)}; transition: background 150ms ease-out, box-shadow 150ms ease-out; }
98
- textarea.oc-sdk-input { height: auto; padding: 8px 12px; resize: vertical; }
198
+ .oc-sdk-input { border-radius: ${controlRadius}; background: ${elevated}; color: ${elevatedFg}; box-shadow: inset 0 0 0 1px ${mix(border, 60)}; transition: background 150ms ease-out, box-shadow 150ms ease-out; }
99
199
  .oc-sdk-input::placeholder { color: ${muted}; }
100
200
  .oc-sdk-input:hover:not(:focus) { background-image: linear-gradient(${hover}, ${hover}); }
101
201
  .oc-sdk-input:focus, .oc-sdk-input:focus-visible { box-shadow: inset 0 0 0 2px ${focus}; }
@@ -103,100 +203,78 @@ textarea.oc-sdk-input { height: auto; padding: 8px 12px; resize: vertical; }
103
203
  .oc-sdk-field[data-invalid="true"] .oc-sdk-input:focus { box-shadow: inset 0 0 0 2px ${v('status-error', 'red')}; }
104
204
  .oc-sdk-input[data-mono="true"] { font-family: ${mono}; }
105
205
 
106
- .oc-sdk-search { position: relative; min-width: 0; }
107
- .oc-sdk-search .oc-sdk-input { padding-left: 34px; padding-right: 34px; }
108
- .oc-sdk-search-icon { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: ${muted}; pointer-events: none; }
206
+ .oc-sdk-search-icon { color: ${muted}; }
109
207
  .oc-sdk-search[data-active="true"] .oc-sdk-search-icon { color: ${primary}; }
110
- .oc-sdk-search-clear { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); display: none; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 6px; color: ${muted}; }
111
- .oc-sdk-search[data-active="true"] .oc-sdk-search-clear { display: inline-flex; }
208
+ .oc-sdk-search-clear { border-radius: ${smallRadius}; color: ${muted}; }
112
209
  .oc-sdk-search-clear:hover { background: ${hover}; color: ${fg}; }
113
210
 
114
- .oc-sdk-select { position: relative; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
115
- .oc-sdk-trigger { display: inline-flex; align-items: center; gap: 6px; width: 100%; min-width: 0; height: 32px; padding: 0 8px 0 10px; border: 1px solid ${border}; border-radius: 6px; background: ${elevated}; color: ${elevatedFg}; font-size: 0.8125rem; text-align: left; transition: background 150ms ease-out; }
211
+ .oc-sdk-trigger { border-color: ${border}; border-radius: ${controlRadius}; background: ${elevated}; color: ${elevatedFg}; transition: background 150ms ease-out; }
116
212
  .oc-sdk-trigger:hover { background-image: linear-gradient(${hover}, ${hover}); }
117
213
  .oc-sdk-trigger[aria-expanded="true"] { background-image: linear-gradient(${active}, ${active}); }
118
- .oc-sdk-trigger-value { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
119
214
  .oc-sdk-trigger-value[data-empty="true"] { color: ${muted}; }
120
- .oc-sdk-trigger-chevron { flex: 0 0 auto; color: ${muted}; }
121
- .oc-sdk-popup { --surface-foreground: ${elevatedFg}; position: fixed; z-index: 50; display: flex; flex-direction: column; gap: 2px; min-width: 160px; max-width: calc(100vw - 16px); max-height: min(320px, calc(100vh - 16px)); overflow: auto; padding: 4px; border: 1px solid ${mix(border, 60)}; border-radius: 12px; background: ${elevated}; color: ${elevatedFg}; box-shadow: 0 8px 24px ${mix(fg, 12)}; }
122
- .oc-sdk-popup-search { flex: 0 0 auto; padding: 2px 2px 4px; }
123
- .oc-sdk-popup-search .oc-sdk-input { height: 32px; font-size: 0.8125rem; }
124
- .oc-sdk-option { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 8px; border-radius: 8px; font-size: 0.8125rem; text-align: left; }
215
+ .oc-sdk-trigger-chevron { color: ${muted}; }
216
+ .oc-sdk-popup { --surface-foreground: ${elevatedFg}; border-color: ${mix(border, 60)}; border-radius: 12px; background: ${elevated}; color: ${elevatedFg}; box-shadow: 0 8px 24px ${mix(fg, 12)}; }
217
+ .oc-sdk-option { border-radius: 8px; }
125
218
  .oc-sdk-option[data-active="true"] { background: ${hover}; }
126
- .oc-sdk-option[aria-selected="true"] { background: ${selection}; color: ${selectionFg}; }
219
+ /* A selected option shows a check mark in the text colour, like the app's own pickers. Options without the mark come
220
+ from bundles built before it existed and keep the selection fill as their only sign of the choice. */
221
+ .oc-sdk-option[aria-selected="true"]:not([data-mark]) { background: ${selection}; color: ${selectionFg}; }
222
+ .oc-sdk-option-check { color: ${fg}; }
127
223
  .oc-sdk-option[data-destructive="true"] { color: ${errorText}; }
128
224
  .oc-sdk-option[data-destructive="true"][data-active="true"] { background: ${mix(v('status-error', 'red'), 10)}; }
129
- .oc-sdk-option-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
130
- .oc-sdk-option-hint { flex: 0 0 auto; font-size: 0.75rem; color: ${muted}; }
131
- .oc-sdk-option-check { flex: 0 0 auto; width: 12px; }
132
- .oc-sdk-popup-empty { padding: 8px; font-size: 0.8125rem; color: ${muted}; }
225
+ .oc-sdk-option-hint { color: ${muted}; }
226
+ .oc-sdk-popup-empty { color: ${muted}; }
133
227
 
134
- .oc-sdk-check { display: inline-flex; align-items: flex-start; gap: 8px; width: 100%; text-align: left; }
135
- .oc-sdk-check-box { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-top: 3px; border: 1px solid ${border}; border-radius: 4px; color: ${primary}; transition: border-color 150ms ease-out; }
136
- .oc-sdk-check[aria-checked="true"] .oc-sdk-check-box { border-color: ${mix(primary, 65, border)}; }
137
- .oc-sdk-check-box > svg { display: none; }
138
- .oc-sdk-check[aria-checked="true"] .oc-sdk-check-box > svg { display: block; }
139
- .oc-sdk-check-thumb { flex: 0 0 auto; position: relative; width: 36px; height: 20px; border-radius: 9999px; background: ${border}; transition: background 150ms ease-out; }
140
- .oc-sdk-check-thumb::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 9999px; background: ${bg}; transition: transform 150ms ease-out; }
228
+ /* Checked stays neutral: the mark carries the state, and the primary colour stays with primary actions. */
229
+ .oc-sdk-check-box { border-color: ${border}; border-radius: 4px; color: ${fg}; transition: border-color 150ms ease-out; }
230
+ .oc-sdk-check[aria-checked="true"] .oc-sdk-check-box { border-color: ${mix(fg, 60, border)}; }
231
+ .oc-sdk-check-thumb { border-radius: 9999px; background: ${border}; transition: background 150ms ease-out; }
232
+ .oc-sdk-check-thumb::after { border-radius: 9999px; background: ${bg}; transition: transform 150ms ease-out; }
141
233
  .oc-sdk-check[aria-checked="true"] .oc-sdk-check-thumb { background: ${primary}; }
142
234
  .oc-sdk-check[aria-checked="true"] .oc-sdk-check-thumb::after { transform: translateX(16px); }
143
235
  .oc-sdk-check:focus-visible { box-shadow: none; }
144
236
  .oc-sdk-check:focus-visible .oc-sdk-check-box, .oc-sdk-check:focus-visible .oc-sdk-check-thumb { ${focusRing} }
145
- .oc-sdk-check-text { display: flex; flex-direction: column; min-width: 0; }
146
- .oc-sdk-check-label { font-size: 0.875rem; }
147
- .oc-sdk-check-desc { font-size: 0.75rem; color: ${muted}; }
237
+ .oc-sdk-check-desc { color: ${muted}; }
148
238
 
149
- .oc-sdk-tabs { display: inline-flex; gap: 2px; padding: 2px; border-radius: 10px; max-width: 100%; overflow: auto; }
239
+ .oc-sdk-tabs { border-radius: 10px; }
150
240
  .oc-sdk-tabs[data-track="true"] { background: ${mix(fg, 4)}; }
151
- .oc-sdk-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px; border: 1px solid transparent; border-radius: 8px; font-size: 0.8125rem; font-weight: 500; color: ${muted}; white-space: nowrap; transition: color 150ms ease-out, background 150ms ease-out; }
241
+ .oc-sdk-tab { border-radius: 8px; color: ${muted}; transition: color 150ms ease-out, background 150ms ease-out; }
152
242
  .oc-sdk-tab:hover { color: ${fg}; }
153
243
  .oc-sdk-tab[aria-selected="true"] { color: ${selectionFg}; background: ${selection}; border-color: ${border}; }
154
- .oc-sdk-tab-count { font-size: 0.75rem; font-variant-numeric: tabular-nums; color: ${muted}; }
244
+ .oc-sdk-tab-count { color: ${muted}; }
155
245
 
156
- .oc-sdk-badge { display: inline-flex; align-items: center; padding: 1px 6px; border-radius: 9999px; font-size: 11px; font-weight: 500; line-height: 16px; white-space: nowrap; background: ${hover}; color: ${muted}; }
246
+ .oc-sdk-badge { border-radius: 9999px; background: ${hover}; color: ${muted}; }
157
247
  .oc-sdk-badge[data-tone] { color: var(--oc-sdk-tone-text, var(--oc-sdk-tone)); background: ${mix('var(--oc-sdk-tone)', 15)}; }
158
248
 
159
- .oc-sdk-list { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
160
- .oc-sdk-row { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 8px; border-radius: 6px; text-align: left; transition: background 120ms ease-out; }
249
+ .oc-sdk-row { border-radius: 6px; transition: background 120ms ease-out; }
161
250
  .oc-sdk-row:hover, .oc-sdk-row[data-active="true"] { background: ${hover}; }
162
251
  .oc-sdk-row[aria-selected="true"] { background: ${selection}; color: ${selectionFg}; }
163
- .oc-sdk-row-lead { flex: 0 0 auto; width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ${mono}; font-size: 0.75rem; color: ${muted}; }
164
- .oc-sdk-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
165
- .oc-sdk-row-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
166
- .oc-sdk-row-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; color: ${muted}; }
167
- .oc-sdk-row-meta { flex: 0 0 auto; font-size: 0.75rem; font-variant-numeric: tabular-nums; color: ${muted}; }
252
+ .oc-sdk-row-lead { font-family: ${mono}; color: ${muted}; }
253
+ .oc-sdk-row-sub { color: ${muted}; }
254
+ .oc-sdk-row-meta { color: ${muted}; }
168
255
  .oc-sdk-row[aria-selected="true"] .oc-sdk-row-lead, .oc-sdk-row[aria-selected="true"] .oc-sdk-row-sub, .oc-sdk-row[aria-selected="true"] .oc-sdk-row-meta { color: inherit; opacity: .75; }
169
- .oc-sdk-list-empty { padding: 16px 8px; text-align: center; font-size: 0.8125rem; color: ${muted}; }
256
+ .oc-sdk-list-empty { color: ${muted}; }
170
257
 
171
- .oc-sdk-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 40px 16px; text-align: center; }
172
- .oc-sdk-empty-title { margin: 0; font-size: 0.8125rem; font-weight: 600; }
173
- .oc-sdk-empty-body { margin: 0; max-width: 32rem; font-size: 0.8125rem; color: ${muted}; }
174
- .oc-sdk-empty-action { margin-top: 12px; }
175
-
176
- @keyframes oc-sdk-spin { to { transform: rotate(360deg); } }
177
- .oc-sdk-spinner { display: inline-flex; align-items: center; gap: 8px; font-size: 0.8125rem; color: ${muted}; }
178
- .oc-sdk-spinner-ring { width: 16px; height: 16px; border: 2px solid ${border}; border-top-color: ${primary}; border-radius: 9999px; animation: oc-sdk-spin .8s linear infinite; }
179
- .oc-sdk-spinner[data-size="sm"] .oc-sdk-spinner-ring { width: 12px; height: 12px; }
258
+ .oc-sdk-empty-body { color: ${muted}; }
180
259
 
181
- .oc-sdk-banner { display: flex; align-items: flex-start; gap: 12px; padding: 8px 12px; border: 1px solid ${mix('var(--oc-sdk-tone)', 40)}; border-radius: 8px; background: ${mix('var(--oc-sdk-tone)', 10)}; }
182
- .oc-sdk-banner-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
183
- .oc-sdk-banner-title { font-size: 0.8125rem; font-weight: 500; color: var(--oc-sdk-tone-text, var(--oc-sdk-tone)); }
184
- .oc-sdk-banner-body { font-size: 0.8125rem; color: ${muted}; }
185
- .oc-sdk-banner-action { flex: 0 0 auto; }
260
+ .oc-sdk-spinner { color: ${muted}; }
261
+ .oc-sdk-spinner-ring { border-color: ${border}; border-top-color: ${primary}; border-radius: 9999px; }
186
262
 
187
- .oc-sdk-separator { display: flex; align-items: center; gap: 8px; width: 100%; margin: 8px 0; font-size: 0.75rem; color: ${muted}; }
188
- .oc-sdk-separator::before, .oc-sdk-separator::after { content: ""; flex: 1 1 auto; height: 1px; background: ${mix(border, 40)}; }
189
- .oc-sdk-separator[data-labeled="false"]::after { display: none; }
190
- .oc-sdk-popup > .oc-sdk-separator { margin: 4px 0; }
263
+ .oc-sdk-banner { border-color: ${mix('var(--oc-sdk-tone)', 40)}; border-radius: 8px; background: ${mix('var(--oc-sdk-tone)', 10)}; }
264
+ .oc-sdk-banner-title { color: var(--oc-sdk-tone-text, var(--oc-sdk-tone)); }
265
+ .oc-sdk-banner-body { color: ${muted}; }
191
266
 
192
- .oc-sdk-progress { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
193
- .oc-sdk-progress-label { display: flex; justify-content: space-between; font-size: 0.75rem; color: ${muted}; font-variant-numeric: tabular-nums; }
194
- .oc-sdk-progress-track { height: 6px; border-radius: 9999px; background: ${border}; overflow: hidden; }
195
- .oc-sdk-progress-fill { height: 100%; border-radius: 9999px; background: var(--oc-sdk-tone, ${primary}); transform-origin: left; transition: transform 200ms ease-out; }
267
+ .oc-sdk-separator { color: ${muted}; }
268
+ .oc-sdk-separator::before, .oc-sdk-separator::after { background: ${mix(border, 40)}; }
196
269
 
197
- .oc-sdk-menu { position: relative; display: inline-flex; }
270
+ .oc-sdk-progress-label { color: ${muted}; }
271
+ .oc-sdk-progress-track { border-radius: 9999px; background: ${border}; }
272
+ .oc-sdk-progress-fill { border-radius: 9999px; background: var(--oc-sdk-tone, ${primary}); }
198
273
 
199
- .oc-sdk-text { white-space: pre-wrap; overflow-wrap: anywhere; }
200
274
  .oc-sdk-text a { color: ${primaryText}; text-decoration: underline; text-underline-offset: 2px; }
201
- .oc-sdk-text img { display: block; max-width: 100%; margin: 8px 0; border-radius: 8px; border: 1px solid ${mix(border, 60)}; }
275
+ .oc-sdk-text img { border-radius: 8px; border: 1px solid ${mix(border, 60)}; }
202
276
  `;
277
+ export const UI_CSS = `
278
+ ${GUEST_SCROLLBAR_CSS}
279
+ ${UI_SIZE_CSS}
280
+ ${GUEST_UI_LOOK_CSS}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openchamber/sdk",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "description": "Contract for OpenChamber guests: manifest parse and iframe host bridge.",
5
5
  "private": false,
6
6
  "license": "MIT",