@xyhp915/slack-base-ui 0.0.1 → 0.0.3

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.
Files changed (54) hide show
  1. package/README.md +220 -4
  2. package/agents/slack-base-ui/SKILL.md +137 -0
  3. package/agents/slack-base-ui/checklists/style-review.md +56 -0
  4. package/agents/slack-base-ui/templates/consumer-setup.md +109 -0
  5. package/agents/slack-base-ui/templates/slack-theme.css +152 -0
  6. package/libs/Dialog.d.ts +73 -0
  7. package/libs/Dialog.d.ts.map +1 -1
  8. package/libs/Popover.d.ts +69 -0
  9. package/libs/Popover.d.ts.map +1 -1
  10. package/libs/index.d.ts +4 -4
  11. package/libs/index.d.ts.map +1 -1
  12. package/libs/index.js +2885 -2718
  13. package/package.json +1 -1
  14. package/src/App.css +7 -0
  15. package/src/App.tsx +18 -0
  16. package/src/assets/react.svg +1 -0
  17. package/src/components/AlertDialog.tsx +185 -0
  18. package/src/components/AutoComplete.tsx +311 -0
  19. package/src/components/Avatar.tsx +70 -0
  20. package/src/components/Badge.tsx +48 -0
  21. package/src/components/Button.tsx +53 -0
  22. package/src/components/Checkbox.tsx +109 -0
  23. package/src/components/ContextMenu.tsx +393 -0
  24. package/src/components/Dialog.tsx +371 -0
  25. package/src/components/Form.tsx +409 -0
  26. package/src/components/IconButton.tsx +49 -0
  27. package/src/components/Input.tsx +56 -0
  28. package/src/components/Loading.tsx +123 -0
  29. package/src/components/Menu.tsx +368 -0
  30. package/src/components/Popover.tsx +367 -0
  31. package/src/components/Progress.tsx +89 -0
  32. package/src/components/Radio.tsx +137 -0
  33. package/src/components/Select.tsx +177 -0
  34. package/src/components/Switch.tsx +116 -0
  35. package/src/components/Tabs.tsx +128 -0
  36. package/src/components/Toast.tsx +149 -0
  37. package/src/components/Tooltip.tsx +46 -0
  38. package/src/components/index.ts +186 -0
  39. package/src/context/ThemeContext.tsx +53 -0
  40. package/src/context/useTheme.ts +11 -0
  41. package/src/examples/slack-clone/SlackApp.tsx +94 -0
  42. package/src/examples/slack-clone/components/ChannelHeader.tsx +34 -0
  43. package/src/examples/slack-clone/components/Composer.tsx +42 -0
  44. package/src/examples/slack-clone/components/Message.tsx +97 -0
  45. package/src/examples/slack-clone/components/UserProfile.tsx +78 -0
  46. package/src/examples/slack-clone/layout/Layout.tsx +27 -0
  47. package/src/examples/slack-clone/layout/Sidebar.tsx +67 -0
  48. package/src/examples/slack-clone/layout/SidebarItem.tsx +57 -0
  49. package/src/examples/slack-clone/layout/TopBar.tsx +30 -0
  50. package/src/index.css +240 -0
  51. package/src/main.tsx +22 -0
  52. package/src/pages/ComponentShowcase.tsx +1964 -0
  53. package/src/pages/Dashboard.tsx +87 -0
  54. package/src/pages/QuickStartDemo.tsx +262 -0
package/README.md CHANGED
@@ -125,6 +125,7 @@ npm run preview
125
125
  - 带有遮罩层和优雅的进入/退出动画
126
126
  - 支持子组件:`DialogBody`、`DialogFooter`、`DialogClose`
127
127
  - 完整的键盘导航和焦点管理
128
+ - **命令式调用**:`DialogProvider` + `useDialog()` hook,支持 `show` / `confirm` / `alert` 三种模式
128
129
 
129
130
  ### AlertDialog - 警告对话框
130
131
  - 基于 Base UI 的 `Dialog` 组件
@@ -158,6 +159,7 @@ npm run preview
158
159
  - 支持四个方向和对齐方式配置
159
160
  - 提供便捷组件:`PopoverHeader`、`PopoverBody`、`PopoverFooter`
160
161
  - 支持受控和非受控模式
162
+ - **命令式调用**:`ImperativePopoverProvider` + `useImperativePopover()` hook,可将 Popover 锚定到任意元素
161
163
  - [详细文档](./docs/POPOVER_MENU_CONTEXTMENU.md#popover-组件)
162
164
 
163
165
  ### Menu - 下拉菜单
@@ -291,14 +293,228 @@ function ConfirmDialog() {
291
293
  }
292
294
  ```
293
295
 
296
+ ## 🚀 命令式 API
297
+
298
+ Dialog 和 Popover 均支持不依赖声明式 JSX、直接用代码调用的**命令式 API**,使用方式与 `useToast()` 完全一致。
299
+
300
+ ### 1. 注册 Provider
301
+
302
+ 在应用根节点(`main.tsx`)包裹对应的 Provider:
303
+
304
+ ```tsx
305
+ // main.tsx
306
+ import { DialogProvider } from './components/Dialog'
307
+ import { ImperativePopoverProvider } from './components/Popover'
308
+
309
+ createRoot(document.getElementById('root')!).render(
310
+ <ThemeProvider>
311
+ <ToastProvider>
312
+ <DialogProvider>
313
+ <ImperativePopoverProvider>
314
+ <App />
315
+ </ImperativePopoverProvider>
316
+ </DialogProvider>
317
+ </ToastProvider>
318
+ </ThemeProvider>
319
+ )
320
+ ```
321
+
322
+ ---
323
+
324
+ ### 2. useDialog — 命令式对话框
325
+
326
+ 在任意子组件中调用 `useDialog()`,获得三个返回 Promise 的方法:
327
+
328
+ | 方法 | 返回值 | 说明 |
329
+ |------|--------|------|
330
+ | `show(options)` | `Promise<void>` | 通用弹窗,关闭后 resolve |
331
+ | `confirm(options)` | `Promise<boolean>` | 确认弹窗,确认 → `true`,取消/关闭 → `false` |
332
+ | `alert(options)` | `Promise<void>` | 仅有 OK 按钮的提示弹窗,点击后 resolve |
333
+
334
+ #### 通用弹窗 `show`
335
+
336
+ ```tsx
337
+ import { useDialog } from './components/Dialog'
338
+
339
+ function MyComponent() {
340
+ const { show } = useDialog()
341
+
342
+ const handleOpen = async () => {
343
+ await show({
344
+ title: '快捷设置',
345
+ content: <SettingsForm />,
346
+ size: 'md',
347
+ })
348
+ console.log('弹窗已关闭')
349
+ }
350
+
351
+ return <Button onClick={handleOpen}>打开设置</Button>
352
+ }
353
+ ```
354
+
355
+ #### 确认弹窗 `confirm`
356
+
357
+ ```tsx
358
+ import { useDialog } from './components/Dialog'
359
+
360
+ function DeleteButton({ onDelete }: { onDelete: () => void }) {
361
+ const { confirm } = useDialog()
362
+
363
+ const handleClick = async () => {
364
+ const ok = await confirm({
365
+ title: '确认删除频道?',
366
+ description: '此操作不可撤销,频道内所有消息将永久删除。',
367
+ confirmLabel: '删除',
368
+ cancelLabel: '取消',
369
+ confirmVariant: 'danger',
370
+ })
371
+ if (ok) onDelete()
372
+ }
373
+
374
+ return <Button variant="danger" onClick={handleClick}>删除频道</Button>
375
+ }
376
+ ```
377
+
378
+ #### 提示弹窗 `alert`
379
+
380
+ ```tsx
381
+ import { useDialog } from './components/Dialog'
382
+
383
+ function SubmitForm() {
384
+ const { alert } = useDialog()
385
+
386
+ const handleSubmit = async () => {
387
+ try {
388
+ await submitData()
389
+ } catch {
390
+ await alert({
391
+ title: '提交失败',
392
+ description: '服务器出现错误,请稍后再试。',
393
+ })
394
+ }
395
+ }
396
+
397
+ return <Button onClick={handleSubmit}>提交</Button>
398
+ }
399
+ ```
400
+
401
+ #### `show` 完整选项
402
+
403
+ ```ts
404
+ interface ShowDialogOptions {
405
+ title?: string // 对话框标题
406
+ description?: string // 标题下方的副文本
407
+ content?: React.ReactNode // 自定义正文内容
408
+ size?: 'sm' | 'md' | 'lg' | 'xl'
409
+ showCloseButton?: boolean // 是否显示右上角关闭按钮,默认 true
410
+ className?: string
411
+ }
412
+ ```
413
+
414
+ #### `confirm` 完整选项
415
+
416
+ ```ts
417
+ interface ConfirmDialogOptions {
418
+ title?: string
419
+ description?: string
420
+ content?: React.ReactNode
421
+ size?: 'sm' | 'md' | 'lg' | 'xl'
422
+ confirmLabel?: string // 默认 'Confirm'
423
+ cancelLabel?: string // 默认 'Cancel'
424
+ confirmVariant?: 'primary' | 'danger' | 'secondary' // 默认 'primary'
425
+ }
426
+ ```
427
+
428
+ #### `alert` 完整选项
429
+
430
+ ```ts
431
+ interface AlertDialogOptions {
432
+ title?: string
433
+ description?: string
434
+ content?: React.ReactNode
435
+ size?: 'sm' | 'md' | 'lg' | 'xl'
436
+ confirmLabel?: string // 默认 'OK'
437
+ }
438
+ ```
439
+
440
+ ---
441
+
442
+ ### 3. useImperativePopover — 命令式浮层
443
+
444
+ 在任意子组件中调用 `useImperativePopover()`,可以将 Popover 锚定到任意 DOM 元素上弹出,无需在 JSX 中手动组合 `<Popover>` + `<PopoverTrigger>`。
445
+
446
+ 全局单例模式:同一时刻只显示一个命令式 Popover。
447
+
448
+ | 方法 / 属性 | 说明 |
449
+ |-------------|------|
450
+ | `show(anchor, options)` | 在指定元素旁弹出 Popover |
451
+ | `hide()` | 关闭当前 Popover |
452
+ | `toggle(anchor, options)` | 同一锚点再次调用时关闭,否则打开 |
453
+ | `isOpen` | 当前是否处于打开状态 |
454
+
455
+ #### 基础用法
456
+
457
+ ```tsx
458
+ import { useImperativePopover } from './components/Popover'
459
+
460
+ function UserCard({ user }: { user: User }) {
461
+ const popover = useImperativePopover()
462
+
294
463
  return (
295
- <Tooltip content="Click to send message">
296
- <Button variant="primary">Send</Button>
297
- </Tooltip>
298
- );
464
+ <button
465
+ onClick={e =>
466
+ popover.show(e.currentTarget, {
467
+ content: <ProfilePanel user={user} />,
468
+ side: 'bottom',
469
+ align: 'start',
470
+ })
471
+ }
472
+ >
473
+ {user.name}
474
+ </button>
475
+ )
476
+ }
477
+ ```
478
+
479
+ #### Toggle 用法(点击再次关闭)
480
+
481
+ ```tsx
482
+ function SettingsButton() {
483
+ const popover = useImperativePopover()
484
+
485
+ return (
486
+ <IconButton
487
+ onClick={e =>
488
+ popover.toggle(e.currentTarget, {
489
+ content: <SettingsPanel onClose={popover.hide} />,
490
+ side: 'bottom',
491
+ align: 'end',
492
+ sideOffset: 4,
493
+ })
494
+ }
495
+ active={popover.isOpen}
496
+ >
497
+ <Settings size={16} />
498
+ </IconButton>
499
+ )
500
+ }
501
+ ```
502
+
503
+ #### `show` / `toggle` 完整选项
504
+
505
+ ```ts
506
+ interface ImperativePopoverOptions {
507
+ content: React.ReactNode // 弹出内容(必填)
508
+ side?: 'top' | 'right' | 'bottom' | 'left' // 默认 'bottom'
509
+ align?: 'start' | 'center' | 'end' // 默认 'center'
510
+ sideOffset?: number // 与锚点的间距,默认 8
511
+ alignOffset?: number // 对齐方向偏移,默认 0
512
+ className?: string // 自定义弹出层样式
299
513
  }
300
514
  ```
301
515
 
516
+ ---
517
+
302
518
  ## 🎬 演示页面
303
519
 
304
520
  项目包含三个主要页面:
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: slack-base-ui
3
+ description: Use this skill whenever a React/Vite project is building with, migrating to, reviewing, or styling around the package @xyhp915/slack-base-ui. It enforces package-level Slack visual consistency, root theme tokens, and component-first adoption rules.
4
+ ---
5
+
6
+ # `@xyhp915/slack-base-ui`
7
+
8
+ This skill is the authoritative guide for AI work involving the UI library `@xyhp915/slack-base-ui`.
9
+
10
+ ## When to use this skill
11
+
12
+ Use this skill whenever the task involves any of the following:
13
+
14
+ - adding `@xyhp915/slack-base-ui` to a project
15
+ - generating pages or components that import from `@xyhp915/slack-base-ui`
16
+ - refactoring an existing UI to adopt this library
17
+ - reviewing a project that already depends on `@xyhp915/slack-base-ui`
18
+ - fixing visual drift in a project that should look like Slack
19
+
20
+ ## Non-negotiable rules
21
+
22
+ 1. **Use the package name exactly as published:** `@xyhp915/slack-base-ui`.
23
+ 2. **Any project that uses this library must keep a unified Slack-style visual language.** Do not mix in Material, shadcn, Ant Design, iOS-glass, neon cyberpunk, or unrelated brand aesthetics.
24
+ 3. **Set the root theme color to Slack** by applying `data-theme-color="slack"` on `document.documentElement`.
25
+ 4. **Dark mode uses the root `.dark` class** on `document.documentElement`.
26
+ 5. **Prefer library components first** (`Button`, `Input`, `Dialog`, `Menu`, `Popover`, `Tabs`, `Toast`, etc.) before creating parallel bespoke UI primitives.
27
+ 6. **Style through Slack-aligned CSS variables** instead of hard-coded one-off colors.
28
+ 7. **Do not switch to `blue`, `green`, or `aubergine` theme-color modes** in consuming apps unless the user explicitly asks to break the unified Slack style rule.
29
+
30
+ ## Verified library facts from the source project
31
+
32
+ - Package identity is declared in `package.json` as `@xyhp915/slack-base-ui`.
33
+ - The library build entry currently points to `src/components/index.ts` via `vite.libs.config.ts`.
34
+ - The public component surface includes foundational components like `Button`, `Avatar`, `Badge`, `Input`, `IconButton`, `Tooltip`, `Dialog`, `AlertDialog`, `Form`, `Select`, `Checkbox`, `Radio`, `Switch`, `Tabs`, `Progress`, `Toast`, `Loading`, `AutoComplete`, `Popover`, `Menu`, and `ContextMenu`.
35
+ - Slack design tokens live in the source project's `src/index.css`.
36
+ - The source app's internal `ThemeProvider` writes both the root `.dark` class and the `data-theme-color` attribute.
37
+ - The current library output is component-focused; do **not** assume the published package automatically injects global Slack theme CSS for consumers.
38
+
39
+ ## Default AI workflow
40
+
41
+ ### 1. Detect adoption state
42
+
43
+ Check whether the target app already:
44
+
45
+ - lists `@xyhp915/slack-base-ui` in dependencies
46
+ - has global CSS tokens for Slack colors and surfaces
47
+ - sets `document.documentElement.dataset.themeColor = 'slack'`
48
+ - uses the root `.dark` class for dark mode
49
+
50
+ ### 2. Establish the Slack theme foundation first
51
+
52
+ Before adding pages or components, make sure the consuming app has:
53
+
54
+ - a global Slack token file
55
+ - root theme initialization
56
+ - Slack-like typography, radius, borders, backgrounds, and focus ring
57
+
58
+ If missing, use the reference template in `templates/slack-theme.css` and the integration guide in `templates/consumer-setup.md`.
59
+
60
+ ### 3. Build with package primitives
61
+
62
+ Prefer imports such as:
63
+
64
+ ```tsx
65
+ import { Button, Input, Dialog, Avatar, Menu, Tabs } from '@xyhp915/slack-base-ui'
66
+ ```
67
+
68
+ When composing new UI:
69
+
70
+ - keep layout dense and productivity-oriented
71
+ - use subdued surfaces and clear borders
72
+ - use Slack aubergine/sidebar accents sparingly and intentionally
73
+ - use green action emphasis and blue selection/focus emphasis
74
+
75
+ ### 4. Prevent visual drift
76
+
77
+ Reject or replace:
78
+
79
+ - oversized rounded "pill everywhere" styling
80
+ - glassmorphism and heavy backdrop blur as a default language
81
+ - pastel gradients as primary surfaces
82
+ - over-animated interaction patterns
83
+ - random per-page color systems unrelated to Slack tokens
84
+
85
+ ### 5. Review before finishing
86
+
87
+ Run the checklist in `checklists/style-review.md` before concluding work.
88
+
89
+ ## Required styling contract for consumer apps
90
+
91
+ Any consumer app using `@xyhp915/slack-base-ui` should satisfy all of these:
92
+
93
+ - root has `data-theme-color="slack"`
94
+ - dark mode toggles `.dark` on `<html>`
95
+ - app-level global CSS defines the Slack token set used by the library
96
+ - custom components continue using the same token family (`--bg-primary`, `--text-primary`, `--accent`, `--accent-action`, `--sidebar-bg`, etc.)
97
+ - app shells, sidebars, lists, dialogs, menus, and inputs visually match the Slack system
98
+
99
+ ## Minimal integration pattern
100
+
101
+ ```tsx
102
+ import { useEffect } from 'react'
103
+
104
+ export function SlackThemeBootstrap() {
105
+ useEffect(() => {
106
+ document.documentElement.setAttribute('data-theme-color', 'slack')
107
+ }, [])
108
+
109
+ return null
110
+ }
111
+ ```
112
+
113
+ For full guidance, use `templates/consumer-setup.md`.
114
+
115
+ ## Decision rules for AI
116
+
117
+ - If the user asks for a new screen in a consumer app, implement it with `@xyhp915/slack-base-ui` components first.
118
+ - If the app already has a conflicting design system, migrate or wrap it toward Slack consistency rather than mixing systems.
119
+ - If custom CSS is required, write it with the Slack token names from this skill.
120
+ - If the user asks for branding changes that would break Slack consistency, call that out explicitly and only proceed if the user wants to override the library standard.
121
+
122
+ ## References inside this skill
123
+
124
+ - `templates/slack-theme.css`
125
+ - `templates/consumer-setup.md`
126
+ - `checklists/style-review.md`
127
+
128
+ ## Output expectation
129
+
130
+ When you finish a task involving this package, the result should:
131
+
132
+ 1. import from `@xyhp915/slack-base-ui`
133
+ 2. keep a consistent Slack-style UI across the project
134
+ 3. preserve the root theme contract (`data-theme-color="slack"`, optional `.dark`)
135
+ 4. avoid aesthetic drift from the library's design system
136
+
137
+
@@ -0,0 +1,56 @@
1
+ # Slack Base UI style review checklist
2
+
3
+ Use this checklist before finishing any task in a project that depends on `@xyhp915/slack-base-ui`.
4
+
5
+ ## Package and component usage
6
+
7
+ - [ ] Imports come from `@xyhp915/slack-base-ui` where equivalent primitives already exist.
8
+ - [ ] No parallel button/input/dialog/menu primitives were added without a clear reason.
9
+ - [ ] New UI uses the library's public component surface before inventing custom controls.
10
+
11
+ ## Theme contract
12
+
13
+ - [ ] `document.documentElement` uses `data-theme-color="slack"`.
14
+ - [ ] Dark mode, if supported, uses the root `.dark` class.
15
+ - [ ] Global CSS includes Slack-compatible tokens required by the library.
16
+ - [ ] Custom styles still read from CSS variables rather than hard-coded palette values.
17
+
18
+ ## Visual consistency
19
+
20
+ - [ ] Sidebars, headers, lists, forms, dialogs, menus, and buttons feel like one Slack-style system.
21
+ - [ ] Primary actions use Slack-style action emphasis instead of arbitrary gradients.
22
+ - [ ] Focus states are visible and token-driven.
23
+ - [ ] Border radius, spacing density, and typography remain productivity-oriented rather than overly playful.
24
+ - [ ] No off-brand aesthetics were introduced: glassmorphism, random gradients, neon effects, or unrelated component-library styling.
25
+
26
+ ## Root tokens to verify
27
+
28
+ At minimum, confirm the host app defines these tokens:
29
+
30
+ - `--accent`
31
+ - `--accent-hover`
32
+ - `--accent-action`
33
+ - `--accent-action-hover`
34
+ - `--accent-contrast`
35
+ - `--bg-primary`
36
+ - `--bg-secondary`
37
+ - `--bg-hover`
38
+ - `--bg-muted`
39
+ - `--text-primary`
40
+ - `--text-secondary`
41
+ - `--text-muted`
42
+ - `--border-light`
43
+ - `--border-active`
44
+ - `--border-subtle`
45
+ - `--sidebar-bg`
46
+ - `--sidebar-text`
47
+ - `--sidebar-text-active`
48
+ - `--sidebar-item-hover`
49
+ - `--sidebar-item-active`
50
+ - `--focus-ring`
51
+ - `--danger`
52
+ - `--danger-hover`
53
+
54
+ ## Final acceptance rule
55
+
56
+ If the package `@xyhp915/slack-base-ui` is present, the finished UI should read as a Slack-style product by default.
@@ -0,0 +1,109 @@
1
+ # Consumer app setup for `@xyhp915/slack-base-ui`
2
+
3
+ Use this template when adding the library to a React/Vite app.
4
+
5
+ ## 1. Install the package
6
+
7
+ ```bash
8
+ npm install @xyhp915/slack-base-ui
9
+ ```
10
+
11
+ ## 2. Add a global Slack theme stylesheet
12
+
13
+ Create or update your app-level global CSS and base it on `templates/slack-theme.css` from this skill.
14
+
15
+ Note: Here is the correct way to load tailwind external contents.
16
+
17
+ ```css
18
+ @source "../node_modules/@xyhp915/slack-base-ui/libs/*.{js,jsx,ts,tsx}";
19
+ ```
20
+
21
+ Example import from your app entry:
22
+
23
+ ```tsx
24
+ import './slack-theme.css'
25
+ import './index.css'
26
+ ```
27
+
28
+ ## 3. Bootstrap the root theme contract
29
+
30
+ Add a tiny initializer so the host app always uses the Slack theme mode expected by the library:
31
+
32
+ ```tsx
33
+ import { useEffect } from 'react'
34
+
35
+ export function SlackThemeBootstrap () {
36
+ useEffect(() => {
37
+ const root = document.documentElement
38
+ root.setAttribute('data-theme-color', 'slack')
39
+
40
+ if (!root.classList.contains('light') && !root.classList.contains('dark')) {
41
+ root.classList.add('light')
42
+ }
43
+ }, [])
44
+
45
+ return null
46
+ }
47
+ ```
48
+
49
+ Mount it near the top of the app:
50
+
51
+ ```tsx
52
+ import { SlackThemeBootstrap } from './SlackThemeBootstrap'
53
+
54
+ export function AppShell () {
55
+ return (
56
+ <>
57
+ <SlackThemeBootstrap/>
58
+ <App/>
59
+ </>
60
+ )
61
+ }
62
+ ```
63
+
64
+ ## 4. Use library components before custom primitives
65
+
66
+ ```tsx
67
+ import { Avatar, Button, Dialog, Input, Tabs } from '@xyhp915/slack-base-ui'
68
+
69
+ export function ChannelInviteDialog () {
70
+ return (
71
+ <div className="flex flex-col gap-4 bg-(--bg-primary) text-(--text-primary)">
72
+ <div className="flex items-center gap-3">
73
+ <Avatar fallback="CD" status="online"/>
74
+ <div>
75
+ <div className="font-bold">Charlie Day</div>
76
+ <div className="text-sm text-(--text-secondary)">Design Systems</div>
77
+ </div>
78
+ </div>
79
+
80
+ <Input label="Invite by email" placeholder="teammate@example.com" fullWidth/>
81
+
82
+ <div className="flex justify-end gap-2">
83
+ <Button variant="secondary">Cancel</Button>
84
+ <Button variant="primary">Send invite</Button>
85
+ </div>
86
+ </div>
87
+ )
88
+ }
89
+ ```
90
+
91
+ ## 5. Dark mode rule
92
+
93
+ If you support dark mode, toggle `.dark` on `document.documentElement`.
94
+ Do not switch `data-theme-color` away from `slack` unless the user explicitly asks to override the design system.
95
+
96
+ ## 6. What to avoid
97
+
98
+ Avoid these patterns in a consumer app that uses `@xyhp915/slack-base-ui`:
99
+
100
+ - mixing in unrelated component libraries for core primitives
101
+ - introducing non-Slack palettes as the default theme
102
+ - replacing token-driven colors with hard-coded brand colors per page
103
+ - using decorative gradients, glass effects, or oversized playful spacing as the baseline UI language
104
+
105
+ ## 7. Important implementation note
106
+
107
+ Based on the current source project, the library build is centered on component exports. Do not assume the package will
108
+ automatically provide the host app with global Slack CSS; make sure the consuming project owns that global theme layer
109
+ explicitly.
@@ -0,0 +1,152 @@
1
+ /* Host-app Slack theme template for @xyhp915/slack-base-ui */
2
+ /* Keep this file global. The consuming app should not swap to a non-Slack baseline unless explicitly requested. */
3
+
4
+ :root {
5
+ --slack-aubergine: #3f0e40;
6
+ --slack-aubergine-dark: #350d36;
7
+ --slack-blue: #1164a3;
8
+ --slack-green: #007a5a;
9
+ --slack-green-hover: #148567;
10
+ --slack-red: #e01e5a;
11
+
12
+ --accent: var(--slack-blue);
13
+ --accent-hover: #0b4c7a;
14
+ --accent-contrast: #ffffff;
15
+ --accent-action: var(--slack-green);
16
+ --accent-action-hover: var(--slack-green-hover);
17
+ --focus-ring: var(--accent);
18
+ --danger: var(--slack-red);
19
+ --danger-hover: #bd1546;
20
+ --badge-neutral: #616061;
21
+
22
+ --bg-primary: #ffffff;
23
+ --bg-secondary: #f8f8f8;
24
+ --bg-hover: #f2f2f2;
25
+ --bg-muted: #f6f6f6;
26
+
27
+ --text-primary: #1d1c1d;
28
+ --text-secondary: #616061;
29
+ --text-muted: #868686;
30
+
31
+ --border-light: #dddddd;
32
+ --border-gray: #767676;
33
+ --border-active: #dddddd;
34
+ --border-subtle: #e6e6e6;
35
+
36
+ --sidebar-bg: var(--slack-aubergine);
37
+ --sidebar-text: #cfc3cf;
38
+ --sidebar-text-active: #ffffff;
39
+ --sidebar-item-hover: #350d36;
40
+ --sidebar-item-active: #1164a3;
41
+
42
+ --space-1: 4px;
43
+ --space-2: 8px;
44
+ --space-3: 12px;
45
+ --space-4: 16px;
46
+ --space-5: 20px;
47
+ --space-6: 24px;
48
+ --space-8: 32px;
49
+
50
+ --font-family: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
51
+ --font-size-sm: 13px;
52
+ --font-size-md: 15px;
53
+ --font-size-lg: 18px;
54
+
55
+ --radius-sm: 3px;
56
+ --radius: 6px;
57
+ --radius-md: 8px;
58
+ --radius-lg: 10px;
59
+ --radius-xl: 14px;
60
+ --radius-2xl: 16px;
61
+ --radius-full: 9999px;
62
+ }
63
+
64
+ :root[data-theme-color='slack'] {
65
+ --accent: var(--slack-blue);
66
+ --accent-hover: #0b4c7a;
67
+ --accent-action: var(--slack-green);
68
+ --accent-action-hover: var(--slack-green-hover);
69
+ }
70
+
71
+ :root.dark {
72
+ --slack-aubergine: #19171d;
73
+ --slack-aubergine-dark: #121016;
74
+
75
+ --bg-primary: #1a1d21;
76
+ --bg-secondary: #222529;
77
+ --bg-hover: #2c3036;
78
+ --bg-muted: #16191d;
79
+
80
+ --text-primary: #d1d2d3;
81
+ --text-secondary: #abacae;
82
+ --text-muted: #858688;
83
+
84
+ --border-light: #363a3e;
85
+ --border-active: transparent;
86
+ --border-subtle: #454545;
87
+ --border-gray: #404040;
88
+
89
+ --sidebar-bg: #19171d;
90
+ --sidebar-text: #abacae;
91
+ --sidebar-text-active: #ffffff;
92
+ --sidebar-item-hover: #27242c;
93
+ --sidebar-item-active: #1164a3;
94
+ }
95
+
96
+ html {
97
+ color-scheme: light;
98
+ }
99
+
100
+ html.dark {
101
+ color-scheme: dark;
102
+ }
103
+
104
+ * {
105
+ box-sizing: border-box;
106
+ }
107
+
108
+ body {
109
+ margin: 0;
110
+ padding: 0;
111
+ font-family: var(--font-family), serif;
112
+ color: var(--text-primary);
113
+ background-color: var(--bg-primary);
114
+ -webkit-font-smoothing: subpixel-antialiased;
115
+ -moz-osx-font-smoothing: grayscale;
116
+ }
117
+
118
+ input:focus-visible,
119
+ textarea:focus-visible,
120
+ button:focus-visible,
121
+ [role='button']:focus-visible {
122
+ outline: 3px solid color-mix(in srgb, var(--focus-ring) 35%, transparent);
123
+ outline-offset: 1px;
124
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--focus-ring) 40%, transparent);
125
+ }
126
+
127
+ ::-webkit-scrollbar {
128
+ width: 8px;
129
+ height: 8px;
130
+ }
131
+
132
+ ::-webkit-scrollbar-track {
133
+ background: transparent;
134
+ }
135
+
136
+ ::-webkit-scrollbar-thumb {
137
+ background: rgba(0, 0, 0, 0.1);
138
+ border-radius: 4px;
139
+ }
140
+
141
+ ::-webkit-scrollbar-thumb:hover {
142
+ background: rgba(0, 0, 0, 0.2);
143
+ }
144
+
145
+ :root.dark ::-webkit-scrollbar-thumb {
146
+ background: rgba(255, 255, 255, 0.1);
147
+ }
148
+
149
+ :root.dark ::-webkit-scrollbar-thumb:hover {
150
+ background: rgba(255, 255, 255, 0.2);
151
+ }
152
+