@data-club/ai-hub 0.0.13 → 0.0.14

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 (35) hide show
  1. package/dist/components/ChatShell/index.d.ts.map +1 -1
  2. package/dist/components/ChatShell/index.js +1 -1
  3. package/dist/components/ChatShell/index.js.map +1 -1
  4. package/dist/components/MainColumn/index.d.ts +13 -0
  5. package/dist/components/MainColumn/index.d.ts.map +1 -1
  6. package/dist/components/MainColumn/index.js +4 -2
  7. package/dist/components/MainColumn/index.js.map +1 -1
  8. package/dist/components/SessionsPanel/index.d.ts +11 -0
  9. package/dist/components/SessionsPanel/index.d.ts.map +1 -1
  10. package/dist/components/SessionsPanel/index.js +76 -41
  11. package/dist/components/SessionsPanel/index.js.map +1 -1
  12. package/dist/context/AIHubContext.d.ts +24 -0
  13. package/dist/context/AIHubContext.d.ts.map +1 -1
  14. package/dist/context/AIHubContext.js.map +1 -1
  15. package/dist/context/AIHubProvider.d.ts +8 -0
  16. package/dist/context/AIHubProvider.d.ts.map +1 -1
  17. package/dist/context/AIHubProvider.js +60 -3
  18. package/dist/context/AIHubProvider.js.map +1 -1
  19. package/dist/context/useAIHub.d.ts +6 -0
  20. package/dist/context/useAIHub.d.ts.map +1 -1
  21. package/dist/context/useAIHub.js +3 -0
  22. package/dist/context/useAIHub.js.map +1 -1
  23. package/dist/stories/_mockProvider.d.ts.map +1 -1
  24. package/dist/stories/_mockProvider.js +3 -0
  25. package/dist/stories/_mockProvider.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/components/ChatShell/index.tsx +1 -0
  28. package/src/components/MainColumn/index.tsx +30 -0
  29. package/src/components/SessionsPanel/index.tsx +77 -4
  30. package/src/context/AIHubContext.ts +26 -0
  31. package/src/context/AIHubProvider.tsx +78 -1
  32. package/src/context/useAIHub.ts +9 -0
  33. package/src/stories/_mockProvider.tsx +3 -0
  34. package/src/styles/CLASSES.md +19 -0
  35. package/src/styles/default.css +284 -0
@@ -114,6 +114,9 @@ export function MockProvider(props: {
114
114
  lastTurnError: opts.lastTurnError ?? null,
115
115
  featureToggles: opts.featureToggles ?? null,
116
116
  refreshFeatureToggles: noopAsync,
117
+ isNarrowLayout: false,
118
+ sessionsDrawerOpen: false,
119
+ setSessionsDrawerOpen: () => undefined,
117
120
  };
118
121
  return (
119
122
  <aiHubContext.Provider value={value}>{props.children}</aiHubContext.Provider>
@@ -26,6 +26,20 @@ properties only, never the attribute directly.
26
26
  .data-club-ai-hub[data-theme="dark"] { --dc-aih-bg: #0f1117; }
27
27
  ```
28
28
 
29
+ ### Layout attribute (responsive)
30
+
31
+ The provider observes the component root's **own width** (ResizeObserver,
32
+ not viewport media queries) and stamps `data-layout="narrow"` or
33
+ `data-layout="wide"` on the same root `<div>`. The breakpoint defaults to
34
+ 720px and is overridable via the provider's `narrowLayoutBreakpoint` prop.
35
+ In the narrow layout the sessions panel renders as an overlay drawer, the
36
+ chat header gains a hamburger button, paddings tighten and touch targets
37
+ grow. Wrappers can scope their own mobile brand tweaks the same way:
38
+
39
+ ```css
40
+ .data-club-ai-hub[data-layout="narrow"] .my-brand-footer { flex-direction: column; }
41
+ ```
42
+
29
43
  ## CSS custom properties (theming tokens)
30
44
 
31
45
  Per-customer wrappers override these to brand the UI; they don't fork the
@@ -204,6 +218,10 @@ block and modifier.
204
218
  | `data-club-ai-hub__layout--panel-right` | Modifier when the panel is on the right. |
205
219
  | `data-club-ai-hub__sessions-panel` | The sessions sidebar. |
206
220
  | `data-club-ai-hub__sessions-panel--collapsed` | Collapsed state (thin reveal strip). |
221
+ | `data-club-ai-hub__sessions-panel--drawer` | Narrow-layout overlay-drawer mode (replaces the inline column). |
222
+ | `data-club-ai-hub__sessions-panel--drawer-open` | Drawer slid in / visible. |
223
+ | `data-club-ai-hub__sessions-panel__scrim` | Backdrop scrim behind the open drawer (`data-open` attribute mirrors the state). |
224
+ | `data-club-ai-hub__sessions-panel__drawer-close` | Close (✕) button at the top of the drawer. |
207
225
  | `data-club-ai-hub__sessions-panel__custom-header` | Slot wrapper at the top of the panel. |
208
226
  | `data-club-ai-hub__sessions-panel__new-button` | "+ New chat" button. |
209
227
  | `data-club-ai-hub__sessions-panel__reveal` | Reveal-strip button shown in collapsed state. |
@@ -229,6 +247,7 @@ block and modifier.
229
247
  | `data-club-ai-hub__main-column` | Right side of the layout (header + body). |
230
248
  | `data-club-ai-hub__main-column__body` | Body region under the chat header. |
231
249
  | `data-club-ai-hub__chat-header` | The strip above the messages with back-link + agent name. |
250
+ | `data-club-ai-hub__chat-header__menu` | Hamburger button opening the sessions drawer (narrow layout only). |
232
251
  | `data-club-ai-hub__chat-header__back` | `[← Agents]` back-to-picker link. |
233
252
  | `data-club-ai-hub__chat-header__title` | Agent display-name text. |
234
253
  | `data-club-ai-hub__chat-header__extras` | Slot for `customHeaderContent`. |
@@ -33,6 +33,10 @@
33
33
  flex-direction: column;
34
34
  height: 100%;
35
35
  min-height: 0;
36
+ /* Positioning context for the narrow-layout overlays (sessions drawer
37
+ + scrim) — they anchor to the component root, not the viewport, so
38
+ partial-width embeds keep the drawer inside their own bounds. */
39
+ position: relative;
36
40
 
37
41
  /* Surface colors */
38
42
  --dc-aih-bg: #ffffff;
@@ -2969,3 +2973,283 @@
2969
2973
  .data-club-ai-hub-admin__fork-rotating-item--selected {
2970
2974
  background-color: color-mix(in srgb, var(--dc-aih-accent) 16%, transparent);
2971
2975
  }
2976
+
2977
+ /* ────────────────────────────────────────────────────────────────────── */
2978
+ /* Responsive — narrow (mobile) layout */
2979
+ /* */
2980
+ /* `<AIHubProvider>` observes the component root's own width with a */
2981
+ /* ResizeObserver and stamps `data-layout="narrow" | "wide"` on */
2982
+ /* `.data-club-ai-hub` (breakpoint 720px by default, overridable via */
2983
+ /* the provider's `narrowLayoutBreakpoint` prop). Every rule below */
2984
+ /* keys off that attribute rather than a viewport media query so the */
2985
+ /* library adapts identically in full-page mounts, iframes, Shadow-DOM */
2986
+ /* widgets and partial-width embeds. */
2987
+ /* */
2988
+ /* In the narrow layout the sessions panel renders as an overlay */
2989
+ /* drawer (`--drawer` modifier + `__scrim`) opened from the hamburger */
2990
+ /* button `<MainColumn>` adds to the chat header. */
2991
+ /* ────────────────────────────────────────────────────────────────────── */
2992
+
2993
+ /* ── Sessions drawer ────────────────────────────────────────────────── */
2994
+
2995
+ /* Backdrop scrim behind the open drawer. Sits above the sticky shell
2996
+ header (z 20) and the header dropdowns (z 30), below modals (z 40). */
2997
+ .data-club-ai-hub__sessions-panel__scrim {
2998
+ position: absolute;
2999
+ inset: 0;
3000
+ z-index: 35;
3001
+ background-color: rgba(0, 0, 0, 0.45);
3002
+ opacity: 0;
3003
+ visibility: hidden;
3004
+ transition: opacity var(--dc-aih-transition),
3005
+ visibility var(--dc-aih-transition);
3006
+ }
3007
+
3008
+ .data-club-ai-hub__sessions-panel__scrim[data-open="true"] {
3009
+ opacity: 1;
3010
+ visibility: visible;
3011
+ }
3012
+
3013
+ .data-club-ai-hub__sessions-panel--drawer {
3014
+ /* Overlay panel anchored to the component root (nearest positioned
3015
+ ancestor — `.data-club-ai-hub` sets `position: relative`). */
3016
+ position: absolute;
3017
+ top: 0;
3018
+ bottom: 0;
3019
+ left: 0;
3020
+ z-index: 36;
3021
+ width: min(320px, 85%);
3022
+ min-width: 0;
3023
+ max-width: none;
3024
+ border-right: 1px solid var(--dc-aih-border);
3025
+ box-shadow: 0 0 32px rgba(0, 0, 0, 0.25);
3026
+ /* Closed: slid off-screen. `visibility` rides the same transition so
3027
+ the panel stays focusable/clickable only while open, without a
3028
+ display toggle that would kill the slide animation. */
3029
+ transform: translateX(-100%);
3030
+ visibility: hidden;
3031
+ transition: transform var(--dc-aih-transition),
3032
+ visibility var(--dc-aih-transition);
3033
+ }
3034
+
3035
+ .data-club-ai-hub__sessions-panel--drawer-open {
3036
+ /* `none` (not `translateX(0)`) — a transformed ancestor becomes the
3037
+ containing block for `position: fixed` descendants, which would
3038
+ trap the session-title modal inside the drawer's box. */
3039
+ transform: none;
3040
+ visibility: visible;
3041
+ }
3042
+
3043
+ /* Right-side drawer when the layout flips the panel side. */
3044
+ .data-club-ai-hub__layout--panel-right .data-club-ai-hub__sessions-panel--drawer {
3045
+ left: auto;
3046
+ right: 0;
3047
+ border-right: none;
3048
+ border-left: 1px solid var(--dc-aih-border);
3049
+ transform: translateX(100%);
3050
+ }
3051
+
3052
+ .data-club-ai-hub__layout--panel-right .data-club-ai-hub__sessions-panel--drawer-open {
3053
+ transform: none;
3054
+ }
3055
+
3056
+ /* Close (✕) button pinned to the drawer's top edge. */
3057
+ .data-club-ai-hub__sessions-panel__drawer-close {
3058
+ align-self: flex-end;
3059
+ flex: 0 0 auto;
3060
+ display: inline-flex;
3061
+ align-items: center;
3062
+ justify-content: center;
3063
+ width: 40px;
3064
+ height: 40px;
3065
+ margin: var(--dc-aih-space-xs) var(--dc-aih-space-xs) 0 0;
3066
+ padding: 0;
3067
+ font: inherit;
3068
+ font-size: var(--dc-aih-font-size-md);
3069
+ color: var(--dc-aih-fg-muted);
3070
+ background: transparent;
3071
+ border: none;
3072
+ border-radius: var(--dc-aih-radius-md);
3073
+ }
3074
+
3075
+ .data-club-ai-hub__sessions-panel__drawer-close:hover {
3076
+ color: var(--dc-aih-fg);
3077
+ background-color: color-mix(in srgb, var(--dc-aih-fg) 6%, transparent);
3078
+ }
3079
+
3080
+ .data-club-ai-hub__sessions-panel__drawer-close:focus-visible {
3081
+ outline: none;
3082
+ box-shadow: 0 0 0 3px var(--dc-aih-focus-ring);
3083
+ }
3084
+
3085
+ /* ── Chat-header hamburger (narrow layout only — MainColumn renders it
3086
+ only while `isNarrowLayout`) ─────────────────────────────────────── */
3087
+
3088
+ .data-club-ai-hub__chat-header__menu {
3089
+ display: inline-flex;
3090
+ align-items: center;
3091
+ justify-content: center;
3092
+ flex: 0 0 auto;
3093
+ width: 40px;
3094
+ height: 40px;
3095
+ margin-left: calc(-1 * var(--dc-aih-space-sm));
3096
+ padding: 0;
3097
+ font: inherit;
3098
+ font-size: 1.25rem;
3099
+ line-height: 1;
3100
+ color: var(--dc-aih-fg);
3101
+ background: transparent;
3102
+ border: none;
3103
+ border-radius: var(--dc-aih-radius-md);
3104
+ }
3105
+
3106
+ .data-club-ai-hub__chat-header__menu:hover {
3107
+ background-color: color-mix(in srgb, var(--dc-aih-fg) 6%, transparent);
3108
+ }
3109
+
3110
+ .data-club-ai-hub__chat-header__menu:focus-visible {
3111
+ outline: none;
3112
+ box-shadow: 0 0 0 3px var(--dc-aih-focus-ring);
3113
+ }
3114
+
3115
+ /* ── Narrow-layout chrome: tighter paddings, full-width bubbles,
3116
+ touch-friendly targets ──────────────────────────────────────────── */
3117
+
3118
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__shell-header {
3119
+ height: 52px;
3120
+ padding: 0 var(--dc-aih-space-md);
3121
+ gap: var(--dc-aih-space-sm);
3122
+ }
3123
+
3124
+ /* Container-width twin of the legacy 480px viewport rule — hide the
3125
+ username next to the avatar whenever the component itself is narrow. */
3126
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__user-menu__username {
3127
+ display: none;
3128
+ }
3129
+
3130
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__user-menu__dropdown,
3131
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__language-switcher__dropdown {
3132
+ max-width: min(280px, calc(100vw - 2 * var(--dc-aih-space-md)));
3133
+ }
3134
+
3135
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__chat-header {
3136
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-md);
3137
+ gap: var(--dc-aih-space-sm);
3138
+ }
3139
+
3140
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__messages {
3141
+ padding: var(--dc-aih-space-md);
3142
+ }
3143
+
3144
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__message-bubble {
3145
+ max-width: 94%;
3146
+ }
3147
+
3148
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__input-area {
3149
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-md);
3150
+ /* Keep the composer clear of the iOS home-indicator strip. */
3151
+ padding-bottom: calc(var(--dc-aih-space-sm) + env(safe-area-inset-bottom, 0px));
3152
+ }
3153
+
3154
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__input-area__send,
3155
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__input-area__stop {
3156
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-md);
3157
+ }
3158
+
3159
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__agents-picker {
3160
+ padding: var(--dc-aih-space-md);
3161
+ }
3162
+
3163
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__login,
3164
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__change-password {
3165
+ padding: var(--dc-aih-space-md);
3166
+ }
3167
+
3168
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__login-card,
3169
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__change-password-card {
3170
+ padding: var(--dc-aih-space-lg);
3171
+ }
3172
+
3173
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__shell-footer {
3174
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-md);
3175
+ }
3176
+
3177
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__modal-overlay {
3178
+ padding: var(--dc-aih-space-md);
3179
+ }
3180
+
3181
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__modal {
3182
+ padding: var(--dc-aih-space-lg);
3183
+ }
3184
+
3185
+ /* Touch screens have no hover — the hover-revealed per-row actions must
3186
+ be always visible, and comfortably tappable, in the narrow layout. */
3187
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__sessions-panel__item-actions {
3188
+ opacity: 1;
3189
+ }
3190
+
3191
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__sessions-panel__action-button {
3192
+ width: 36px;
3193
+ height: 36px;
3194
+ }
3195
+
3196
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub__sessions-panel__item-title {
3197
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-xs);
3198
+ }
3199
+
3200
+ /* ── Narrow-layout admin: stacked nav bar + scrollable tables ───────── */
3201
+
3202
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__body {
3203
+ flex-direction: column;
3204
+ }
3205
+
3206
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__nav {
3207
+ flex: 0 0 auto;
3208
+ flex-direction: row;
3209
+ align-items: center;
3210
+ gap: var(--dc-aih-space-xs);
3211
+ padding: var(--dc-aih-space-sm) var(--dc-aih-space-md);
3212
+ border-right: none;
3213
+ border-bottom: 1px solid var(--dc-aih-border);
3214
+ overflow-x: auto;
3215
+ }
3216
+
3217
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__nav-heading {
3218
+ display: none;
3219
+ }
3220
+
3221
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__nav-list {
3222
+ flex-direction: row;
3223
+ gap: var(--dc-aih-space-xs);
3224
+ }
3225
+
3226
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__nav-item {
3227
+ width: auto;
3228
+ white-space: nowrap;
3229
+ }
3230
+
3231
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__nav-exit {
3232
+ width: auto;
3233
+ margin-top: 0;
3234
+ margin-left: auto;
3235
+ white-space: nowrap;
3236
+ }
3237
+
3238
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__content {
3239
+ padding: var(--dc-aih-space-md);
3240
+ }
3241
+
3242
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__page-header {
3243
+ flex-wrap: wrap;
3244
+ }
3245
+
3246
+ /* Wide data tables scroll inside their own box instead of stretching
3247
+ the page. `display: block` keeps the inner table layout intact while
3248
+ letting the element itself clip + scroll horizontally. */
3249
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__users-table,
3250
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__agents-table,
3251
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__sessions-table,
3252
+ .data-club-ai-hub[data-layout="narrow"] .data-club-ai-hub-admin__rotating-table {
3253
+ display: block;
3254
+ overflow-x: auto;
3255
+ }