srcdev-nuxt-components 9.6.18 → 9.6.19
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/.claude/rules/consumer/css-relative-colour-calc.md +15 -0
- package/.claude/rules/consumer/vue-dynamic-arg-no-spaces.md +16 -0
- package/.claude/skills/component-compliance-checklist.md +6 -1
- package/.claude/skills/component-dynamic-slots.md +2 -2
- package/.claude/skills/component-naming.md +1 -1
- package/.claude/skills/components/accordion-chat.md +99 -0
- package/.claude/skills/components/accordion-group.md +98 -0
- package/.claude/skills/components/action-menu.md +11 -5
- package/.claude/skills/components/expanding-panel-classic.md +9 -7
- package/.claude/skills/components/expanding-panel.md +9 -8
- package/.claude/skills/components/sparkle-effect.md +79 -0
- package/.claude/skills/index.md +4 -2
- package/.claude/skills/storybook-add-story.md +8 -0
- package/.claude/skills/using-component-skills.md +1 -1
- package/.vscode/srcdev-component-accordion-chat.code-snippets +42 -0
- package/.vscode/srcdev-component-accordion-group.code-snippets +38 -0
- package/.vscode/srcdev-component-action-menu.code-snippets +3 -3
- package/.vscode/srcdev-component-sparkle-effect.code-snippets +33 -0
- package/app/components/01.atoms/animations/sparkle-effect/CONSUMER-STYLING.md +75 -0
- package/app/components/01.atoms/animations/sparkle-effect/SparkleEffect.vue +213 -0
- package/app/components/01.atoms/animations/sparkle-effect/stories/SparkleEffect.stories.ts +303 -0
- package/app/components/01.atoms/animations/sparkle-effect/tests/SparkleEffect.spec.ts +150 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +1 -1
- package/app/components/02.molecules/action-menu/ActionMenu.vue +6 -2
- package/app/components/02.molecules/action-menu/ActionMenuItem.vue +6 -3
- package/app/components/02.molecules/action-menu/CONSUMER-STYLING.md +11 -4
- package/app/components/02.molecules/action-menu/stories/ActionMenu.stories.ts +130 -18
- package/app/components/02.molecules/expandable/accordion-chat/AccordionChat.vue +227 -0
- package/app/components/02.molecules/expandable/accordion-chat/CONSUMER-STYLING.md +150 -0
- package/app/components/02.molecules/expandable/accordion-chat/stories/AccordionChat.stories.ts +347 -0
- package/app/components/02.molecules/expandable/accordion-chat/tests/AccordionChat.spec.ts +205 -0
- package/app/components/02.molecules/expandable/accordion-chat/tests/__snapshots__/AccordionChat.spec.ts.snap +40 -0
- package/app/components/02.molecules/expandable/{accordian/AccordianCore.vue → accordion-group/AccordionGroup.vue} +32 -20
- package/app/components/02.molecules/expandable/accordion-group/CONSUMER-STYLING.md +66 -0
- package/app/components/02.molecules/expandable/accordion-group/stories/AccordionGroup.stories.ts +238 -0
- package/app/components/02.molecules/expandable/accordion-group/tests/AccordionGroup.spec.ts +172 -0
- package/app/components/02.molecules/expandable/accordion-group/tests/__snapshots__/AccordionGroup.spec.ts.snap +45 -0
- package/app/components/02.molecules/expandable/expanding-panel/CONSUMER-STYLING.md +1 -0
- package/app/components/02.molecules/expandable/expanding-panel/ExpandingPanel.vue +11 -6
- package/app/components/02.molecules/expandable/expanding-panel/stories/ExpandingPanel.stories.ts +82 -1
- package/app/components/02.molecules/expandable/expanding-panel/tests/ExpandingPanel.spec.ts +24 -30
- package/app/components/02.molecules/expandable/expanding-panel/tests/__snapshots__/ExpandingPanel.spec.ts.snap +8 -8
- package/app/components/02.molecules/expandable/expanding-panel-classic/CONSUMER-STYLING.md +1 -0
- package/app/components/02.molecules/expandable/expanding-panel-classic/ExpandingPanelClassic.vue +10 -5
- package/app/components/02.molecules/expandable/expanding-panel-classic/stories/ExpandingPanelClassic.stories.ts +83 -1
- package/app/components/02.molecules/expandable/expanding-panel-classic/tests/ExpandingPanelClassic.spec.ts +24 -30
- package/app/components/02.molecules/expandable/expanding-panel-classic/tests/__snapshots__/ExpandingPanelClassic.spec.ts.snap +8 -8
- package/app/components/03.organisms/responsive-header/tests/__snapshots__/NavigationItems.spec.ts.snap +2 -2
- package/app/components/03.organisms/responsive-header/tests/__snapshots__/ResponsiveHeader.spec.ts.snap +2 -2
- package/package.json +1 -1
- package/.claude/skills/components/accordian-core.md +0 -180
- package/.vscode/srcdev-component-accordian-core.code-snippets +0 -74
- package/app/components/02.molecules/expandable/accordian/CONSUMER-STYLING.md +0 -100
- package/app/components/02.molecules/expandable/accordian/stories/AccordianCore.stories.ts +0 -272
- package/app/components/02.molecules/expandable/accordian/tests/AccordianCore.spec.ts +0 -257
- package/app/components/02.molecules/expandable/accordian/tests/__snapshots__/AccordianCore.spec.ts.snap +0 -95
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="accordion-chat" :class="elementClasses">
|
|
3
|
+
<ExpandingPanelClassic
|
|
4
|
+
v-for="index in panelIndexes()"
|
|
5
|
+
:key="index"
|
|
6
|
+
:name
|
|
7
|
+
:animation-duration="animationDuration"
|
|
8
|
+
:style-class-passthrough="['accordion-chat-item']"
|
|
9
|
+
>
|
|
10
|
+
<template #summary>
|
|
11
|
+
<slot :name="`item-${index}-summary`"></slot>
|
|
12
|
+
</template>
|
|
13
|
+
<template #icon>
|
|
14
|
+
<slot :name="`item-${index}-icon`">
|
|
15
|
+
<span class="accordion-chat-icon" aria-hidden="true">
|
|
16
|
+
<Icon name="lucide:plus" class="accordion-chat-icon-glyph" />
|
|
17
|
+
</span>
|
|
18
|
+
</slot>
|
|
19
|
+
</template>
|
|
20
|
+
<template #content>
|
|
21
|
+
<div v-if="slots[`item-${index}-content`]" class="accordion-chat-answer">
|
|
22
|
+
<span v-if="hasAvatar(index)" class="accordion-chat-avatar" aria-hidden="true">
|
|
23
|
+
<slot :name="`item-${index}-avatar`">
|
|
24
|
+
<slot name="avatar">{{ avatarInitials }}</slot>
|
|
25
|
+
</slot>
|
|
26
|
+
</span>
|
|
27
|
+
<div class="accordion-chat-bubble">
|
|
28
|
+
<slot :name="`item-${index}-content`"></slot>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
</ExpandingPanelClassic>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
import ExpandingPanelClassic from "../expanding-panel-classic/ExpandingPanelClassic.vue";
|
|
38
|
+
|
|
39
|
+
interface Props {
|
|
40
|
+
name?: string;
|
|
41
|
+
animationDuration?: number;
|
|
42
|
+
avatarLabel?: string;
|
|
43
|
+
showAvatar?: boolean;
|
|
44
|
+
styleClassPassthrough?: string | string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
48
|
+
name: undefined,
|
|
49
|
+
animationDuration: 300,
|
|
50
|
+
avatarLabel: "",
|
|
51
|
+
showAvatar: true,
|
|
52
|
+
styleClassPassthrough: () => [],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const slots = useSlots();
|
|
56
|
+
const SUMMARY_SLOT = /^item-(\d+)-summary$/;
|
|
57
|
+
|
|
58
|
+
const panelIndexes = () =>
|
|
59
|
+
Object.keys(slots)
|
|
60
|
+
.map((slotName) => SUMMARY_SLOT.exec(slotName)?.[1])
|
|
61
|
+
.filter((index): index is string => index !== undefined)
|
|
62
|
+
.map(Number)
|
|
63
|
+
.sort((a, b) => a - b);
|
|
64
|
+
|
|
65
|
+
const toGraphemes = (text: string) =>
|
|
66
|
+
typeof Intl.Segmenter === "function"
|
|
67
|
+
? Array.from(new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(text), ({ segment }) => segment)
|
|
68
|
+
: Array.from(text);
|
|
69
|
+
|
|
70
|
+
const avatarInitials = computed(() => toGraphemes(props.avatarLabel.trim()).slice(0, 2).join(""));
|
|
71
|
+
|
|
72
|
+
const hasAvatar = (index: number) =>
|
|
73
|
+
props.showAvatar && Boolean(slots[`item-${index}-avatar`] || slots.avatar || avatarInitials.value);
|
|
74
|
+
|
|
75
|
+
const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
76
|
+
|
|
77
|
+
watch(
|
|
78
|
+
() => props.styleClassPassthrough,
|
|
79
|
+
() => {
|
|
80
|
+
resetElementClasses(props.styleClassPassthrough);
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<style lang="css">
|
|
86
|
+
@layer components {
|
|
87
|
+
.accordion-chat {
|
|
88
|
+
--_accordion-chat-radius: var(--accordion-chat-radius, 2rem);
|
|
89
|
+
--_accordion-chat-tail-radius: var(--accordion-chat-tail-radius, 0.6rem);
|
|
90
|
+
--_accordion-chat-bubble-max-width: var(--accordion-chat-bubble-max-width, 82%);
|
|
91
|
+
--_accordion-chat-duration: var(--accordion-chat-transition-duration, 200ms);
|
|
92
|
+
|
|
93
|
+
display: grid;
|
|
94
|
+
gap: var(--accordion-chat-gap, 1.4rem);
|
|
95
|
+
|
|
96
|
+
.accordion-chat-item.expanding-panel-classic {
|
|
97
|
+
--expanding-panel-classic-icon-size: var(--accordion-chat-icon-size, 2.2rem);
|
|
98
|
+
--expanding-panel-classic-summary-gap: var(--accordion-chat-question-icon-gap, 1.4rem);
|
|
99
|
+
|
|
100
|
+
.expanding-panel-classic-summary {
|
|
101
|
+
inline-size: fit-content;
|
|
102
|
+
max-inline-size: var(--_accordion-chat-bubble-max-width);
|
|
103
|
+
margin-inline-start: auto;
|
|
104
|
+
padding-block: var(--accordion-chat-question-padding-block, 1.3rem);
|
|
105
|
+
padding-inline: var(--accordion-chat-question-padding-inline, 2rem 1.8rem);
|
|
106
|
+
border: var(--accordion-chat-question-border-width, 0.1rem) solid
|
|
107
|
+
var(--accordion-chat-question-border, transparent);
|
|
108
|
+
border-radius: var(--_accordion-chat-radius);
|
|
109
|
+
border-end-end-radius: var(--_accordion-chat-tail-radius);
|
|
110
|
+
background-color: var(--accordion-chat-question-surface, var(--theme-surface-subtle));
|
|
111
|
+
color: var(--accordion-chat-question-colour, var(--theme-text));
|
|
112
|
+
font-family: var(--accordion-chat-question-font-family, inherit);
|
|
113
|
+
font-size: var(--accordion-chat-question-font-size, 1.6rem);
|
|
114
|
+
font-weight: var(--accordion-chat-question-font-weight, 600);
|
|
115
|
+
line-height: var(--accordion-chat-question-line-height, 1.3);
|
|
116
|
+
transition:
|
|
117
|
+
background-color var(--_accordion-chat-duration),
|
|
118
|
+
color var(--_accordion-chat-duration),
|
|
119
|
+
border-color var(--_accordion-chat-duration);
|
|
120
|
+
|
|
121
|
+
&:focus-visible {
|
|
122
|
+
outline: var(--accordion-chat-focus-ring-width, 0.2rem) solid
|
|
123
|
+
var(--accordion-chat-focus-ring-colour, var(--theme-border-focus));
|
|
124
|
+
outline-offset: 0.2rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.expanding-panel-classic-details[open] & {
|
|
128
|
+
border-color: var(--accordion-chat-question-border-open, var(--accordion-chat-question-border, transparent));
|
|
129
|
+
background-color: var(--accordion-chat-question-surface-open, var(--theme-surface-inverted));
|
|
130
|
+
color: var(--accordion-chat-question-colour-open, var(--theme-text-inverted));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.accordion-chat-icon {
|
|
134
|
+
display: grid;
|
|
135
|
+
place-items: center;
|
|
136
|
+
inline-size: 100%;
|
|
137
|
+
aspect-ratio: 1;
|
|
138
|
+
border-radius: 50%;
|
|
139
|
+
background-color: var(--accordion-chat-icon-surface, rgb(0 0 0 / 0.07));
|
|
140
|
+
|
|
141
|
+
.expanding-panel-classic-details[open] & {
|
|
142
|
+
background-color: var(--accordion-chat-icon-surface-open, rgb(255 255 255 / 0.16));
|
|
143
|
+
rotate: 45deg;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
147
|
+
transition:
|
|
148
|
+
background-color var(--_accordion-chat-duration),
|
|
149
|
+
rotate calc(var(--_accordion-chat-duration) * 1.25);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.accordion-chat-icon-glyph {
|
|
153
|
+
display: block;
|
|
154
|
+
font-size: var(--accordion-chat-icon-glyph-size, 1.4rem);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.accordion-chat-answer {
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: flex-end;
|
|
163
|
+
gap: var(--accordion-chat-avatar-gap, 1rem);
|
|
164
|
+
padding-block-start: var(--accordion-chat-answer-gap, 1rem);
|
|
165
|
+
|
|
166
|
+
.accordion-chat-avatar {
|
|
167
|
+
flex: none;
|
|
168
|
+
display: grid;
|
|
169
|
+
place-items: center;
|
|
170
|
+
inline-size: var(--accordion-chat-avatar-size, 3rem);
|
|
171
|
+
aspect-ratio: 1;
|
|
172
|
+
overflow: hidden;
|
|
173
|
+
border-radius: 50%;
|
|
174
|
+
background-color: var(--accordion-chat-avatar-surface, var(--theme-surface-inverted));
|
|
175
|
+
color: var(--accordion-chat-avatar-colour, var(--theme-text-inverted));
|
|
176
|
+
font-family: var(--accordion-chat-avatar-font-family, inherit);
|
|
177
|
+
font-size: var(--accordion-chat-avatar-font-size, 1.2rem);
|
|
178
|
+
font-weight: var(--accordion-chat-avatar-font-weight, 600);
|
|
179
|
+
line-height: 1;
|
|
180
|
+
white-space: nowrap;
|
|
181
|
+
|
|
182
|
+
& :where(img, svg) {
|
|
183
|
+
inline-size: 100%;
|
|
184
|
+
block-size: 100%;
|
|
185
|
+
object-fit: cover;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.accordion-chat-bubble {
|
|
190
|
+
min-inline-size: 0;
|
|
191
|
+
max-inline-size: var(--_accordion-chat-bubble-max-width);
|
|
192
|
+
padding-block: var(--accordion-chat-answer-padding-block, 1.4rem);
|
|
193
|
+
padding-inline: var(--accordion-chat-answer-padding-inline, 1.8rem);
|
|
194
|
+
border: var(--accordion-chat-answer-border-width, 0.1rem) solid
|
|
195
|
+
var(--accordion-chat-answer-border, var(--theme-surface-subtle));
|
|
196
|
+
border-radius: var(--_accordion-chat-radius);
|
|
197
|
+
border-end-start-radius: var(--_accordion-chat-tail-radius);
|
|
198
|
+
background-color: var(--accordion-chat-answer-surface, var(--theme-text-inverted));
|
|
199
|
+
color: var(--accordion-chat-answer-colour, var(--theme-text));
|
|
200
|
+
font-family: var(--accordion-chat-answer-font-family, inherit);
|
|
201
|
+
font-size: var(--accordion-chat-answer-font-size, 1.55rem);
|
|
202
|
+
font-weight: var(--accordion-chat-answer-font-weight, 400);
|
|
203
|
+
line-height: var(--accordion-chat-answer-line-height, 1.6);
|
|
204
|
+
|
|
205
|
+
& :where(img, video) {
|
|
206
|
+
max-inline-size: 100%;
|
|
207
|
+
block-size: auto;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
211
|
+
.expanding-panel-classic-details[open] + .expanding-panel-classic-content & {
|
|
212
|
+
animation: accordion-chat-answer-in var(--accordion-chat-entrance-duration, 260ms) ease-out both;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@keyframes accordion-chat-answer-in {
|
|
220
|
+
from {
|
|
221
|
+
opacity: 0;
|
|
222
|
+
translate: 0 0.6rem;
|
|
223
|
+
scale: 0.98;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
</style>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# AccordionChat — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
Every visual property is a token. The defaults take colours from the `--theme-*` slots; the
|
|
4
|
+
Storybook **Default** and **Dark Theme** stories are two complete token sets for the same markup, to
|
|
5
|
+
copy from.
|
|
6
|
+
|
|
7
|
+
## Public token API
|
|
8
|
+
|
|
9
|
+
### Layout and shape (resolved on `.accordion-chat`)
|
|
10
|
+
|
|
11
|
+
| Token | Default | Controls |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `--accordion-chat-gap` | `1.4rem` | Space between panels |
|
|
14
|
+
| `--accordion-chat-answer-gap` | `1rem` | Space between a question and its answer |
|
|
15
|
+
| `--accordion-chat-bubble-max-width` | `82%` | Maximum width of both bubbles |
|
|
16
|
+
| `--accordion-chat-radius` | `2rem` | Bubble corner radius |
|
|
17
|
+
| `--accordion-chat-tail-radius` | `0.6rem` | The "tail" corner: bottom-end of the question, bottom-start of the answer (logical, so it flips in RTL) |
|
|
18
|
+
| `--accordion-chat-transition-duration` | `200ms` | Question colour change; the icon rotation takes 1.25× this |
|
|
19
|
+
| `--accordion-chat-entrance-duration` | `260ms` | Answer bubble fade-and-settle when it opens |
|
|
20
|
+
| `--accordion-chat-focus-ring-width` | `0.2rem` | Question focus outline width |
|
|
21
|
+
| `--accordion-chat-focus-ring-colour` | `var(--theme-border-focus)` | Question focus outline colour |
|
|
22
|
+
|
|
23
|
+
### Question bubble (the panel's `summary`)
|
|
24
|
+
|
|
25
|
+
| Token | Default | Controls |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `--accordion-chat-question-surface` | `var(--theme-surface-subtle)` | Background, closed |
|
|
28
|
+
| `--accordion-chat-question-colour` | `var(--theme-text)` | Text, closed |
|
|
29
|
+
| `--accordion-chat-question-border` | `transparent` | Border colour, closed |
|
|
30
|
+
| `--accordion-chat-question-surface-open` | `var(--theme-surface-inverted)` | Background, open |
|
|
31
|
+
| `--accordion-chat-question-colour-open` | `var(--theme-text-inverted)` | Text, open |
|
|
32
|
+
| `--accordion-chat-question-border-open` | `var(--accordion-chat-question-border)` | Border colour, open |
|
|
33
|
+
| `--accordion-chat-question-border-width` | `0.1rem` | Border width |
|
|
34
|
+
| `--accordion-chat-question-font-family` | `inherit` | Font family |
|
|
35
|
+
| `--accordion-chat-question-font-size` | `1.6rem` | Font size |
|
|
36
|
+
| `--accordion-chat-question-font-weight` | `600` | Font weight |
|
|
37
|
+
| `--accordion-chat-question-line-height` | `1.3` | Line height |
|
|
38
|
+
| `--accordion-chat-question-padding-block` | `1.3rem` | Vertical padding |
|
|
39
|
+
| `--accordion-chat-question-padding-inline` | `2rem 1.8rem` | Start and end padding |
|
|
40
|
+
| `--accordion-chat-question-icon-gap` | `1.4rem` | Space between the text and the icon |
|
|
41
|
+
|
|
42
|
+
### Icon (default `+` that turns to `×` when open)
|
|
43
|
+
|
|
44
|
+
| Token | Default | Controls |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `--accordion-chat-icon-size` | `2.2rem` | Icon circle size |
|
|
47
|
+
| `--accordion-chat-icon-glyph-size` | `1.4rem` | The `+` glyph size |
|
|
48
|
+
| `--accordion-chat-icon-surface` | `rgb(0 0 0 / 0.07)` | Circle fill, closed |
|
|
49
|
+
| `--accordion-chat-icon-surface-open` | `rgb(255 255 255 / 0.16)` | Circle fill, open |
|
|
50
|
+
|
|
51
|
+
The glyph takes the question's text colour.
|
|
52
|
+
|
|
53
|
+
### Answer bubble
|
|
54
|
+
|
|
55
|
+
| Token | Default | Controls |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `--accordion-chat-answer-surface` | `var(--theme-text-inverted)` | Background (the lightest theme step) |
|
|
58
|
+
| `--accordion-chat-answer-colour` | `var(--theme-text)` | Text |
|
|
59
|
+
| `--accordion-chat-answer-border` | `var(--theme-surface-subtle)` | Border colour |
|
|
60
|
+
| `--accordion-chat-answer-border-width` | `0.1rem` | Border width |
|
|
61
|
+
| `--accordion-chat-answer-font-family` | `inherit` | Font family |
|
|
62
|
+
| `--accordion-chat-answer-font-size` | `1.55rem` | Font size |
|
|
63
|
+
| `--accordion-chat-answer-font-weight` | `400` | Font weight |
|
|
64
|
+
| `--accordion-chat-answer-line-height` | `1.6` | Line height |
|
|
65
|
+
| `--accordion-chat-answer-padding-block` | `1.4rem` | Vertical padding |
|
|
66
|
+
| `--accordion-chat-answer-padding-inline` | `1.8rem` | Horizontal padding |
|
|
67
|
+
|
|
68
|
+
### Avatar
|
|
69
|
+
|
|
70
|
+
| Token | Default | Controls |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `--accordion-chat-avatar-size` | `3rem` | Circle size |
|
|
73
|
+
| `--accordion-chat-avatar-gap` | `1rem` | Space between avatar and bubble |
|
|
74
|
+
| `--accordion-chat-avatar-surface` | `var(--theme-surface-inverted)` | Circle fill |
|
|
75
|
+
| `--accordion-chat-avatar-colour` | `var(--theme-text-inverted)` | Initials colour |
|
|
76
|
+
| `--accordion-chat-avatar-font-family` | `inherit` | Initials font |
|
|
77
|
+
| `--accordion-chat-avatar-font-size` | `1.2rem` | Initials size |
|
|
78
|
+
| `--accordion-chat-avatar-font-weight` | `600` | Initials weight |
|
|
79
|
+
|
|
80
|
+
Private (not public API): `--_accordion-chat-radius`, `--_accordion-chat-tail-radius`,
|
|
81
|
+
`--_accordion-chat-bubble-max-width` and `--_accordion-chat-duration`, each read by several rules.
|
|
82
|
+
|
|
83
|
+
## State hooks
|
|
84
|
+
|
|
85
|
+
| Selector | Meaning |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `.accordion-chat` | Root |
|
|
88
|
+
| `.accordion-chat-item` | Each panel (an `ExpandingPanelClassic` root) |
|
|
89
|
+
| `.accordion-chat-item .expanding-panel-classic-details[open]` | That panel is open |
|
|
90
|
+
| `.accordion-chat-item .expanding-panel-classic-summary` | Question bubble |
|
|
91
|
+
| `.accordion-chat-icon`, `.accordion-chat-icon-glyph` | Default icon circle and glyph |
|
|
92
|
+
| `.accordion-chat-answer` | Answer row (avatar + bubble), inside the panel's `.inner` |
|
|
93
|
+
| `.accordion-chat-avatar` | Avatar circle (`aria-hidden`) |
|
|
94
|
+
| `.accordion-chat-bubble` | Answer bubble |
|
|
95
|
+
|
|
96
|
+
## Motion
|
|
97
|
+
|
|
98
|
+
Opening animates the row height (ExpandingPanelClassic, `grid-template-rows`, every browser), then
|
|
99
|
+
the answer bubble fades in and settles from a slight offset. Under `prefers-reduced-motion: reduce`
|
|
100
|
+
the entrance animation and the icon rotation's transition are off; colours still change.
|
|
101
|
+
|
|
102
|
+
## Local overrides
|
|
103
|
+
|
|
104
|
+
Set the tokens above on an element you own (a page or section class, or a class added with
|
|
105
|
+
`:style-class-passthrough`): they inherit down into the component. Keep the block **unlayered** (no
|
|
106
|
+
`@layer` wrapper) so it beats the library's `@layer components`. If your own file uses
|
|
107
|
+
`<style scoped>`, tokens set on your element still work, but selectors that reach inside the component need
|
|
108
|
+
`:deep()`. Patterns and examples: `.claude/skills/component-local-style-override.md`.
|
|
109
|
+
|
|
110
|
+
**Caveat:** each panel re-declares `--expanding-panel-classic-icon-size` and
|
|
111
|
+
`--expanding-panel-classic-summary-gap` from `--accordion-chat-icon-size` and
|
|
112
|
+
`--accordion-chat-question-icon-gap`, so set those `--accordion-chat-*` tokens; an ancestor's
|
|
113
|
+
`--expanding-panel-classic-*` value for them never lands.
|
|
114
|
+
|
|
115
|
+
## Recipe: dark, serif theme
|
|
116
|
+
|
|
117
|
+
```css
|
|
118
|
+
.faq-section {
|
|
119
|
+
--accordion-chat-question-font-family: "Playfair Display", Georgia, serif;
|
|
120
|
+
--accordion-chat-question-font-size: 1.9rem;
|
|
121
|
+
--accordion-chat-question-font-weight: 400;
|
|
122
|
+
--accordion-chat-question-surface: #1a1615;
|
|
123
|
+
--accordion-chat-question-colour: #f2ece2;
|
|
124
|
+
--accordion-chat-question-border: #2b2422;
|
|
125
|
+
--accordion-chat-question-surface-open: #c9a961;
|
|
126
|
+
--accordion-chat-question-colour-open: #14100f;
|
|
127
|
+
--accordion-chat-question-border-open: #c9a961;
|
|
128
|
+
--accordion-chat-icon-surface: rgb(255 255 255 / 0.08);
|
|
129
|
+
--accordion-chat-icon-surface-open: rgb(0 0 0 / 0.12);
|
|
130
|
+
--accordion-chat-answer-surface: #1a1615;
|
|
131
|
+
--accordion-chat-answer-border: #2b2422;
|
|
132
|
+
--accordion-chat-answer-colour: #cbbfb4;
|
|
133
|
+
--accordion-chat-answer-font-weight: 300;
|
|
134
|
+
--accordion-chat-answer-line-height: 1.7;
|
|
135
|
+
--accordion-chat-avatar-surface: #c9a961;
|
|
136
|
+
--accordion-chat-avatar-colour: #14100f;
|
|
137
|
+
--accordion-chat-focus-ring-colour: #c9a961;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Class passthrough
|
|
142
|
+
|
|
143
|
+
`style-class-passthrough` adds classes to the root `.accordion-chat` (reactive after mount). Panels
|
|
144
|
+
always get `.accordion-chat-item`.
|
|
145
|
+
|
|
146
|
+
## Notes
|
|
147
|
+
|
|
148
|
+
- The answer bubble is a wrapper inside the panel's `#content` slot. Never style the panel's
|
|
149
|
+
`.inner` (it must keep `overflow: hidden` and no padding for the row-height animation).
|
|
150
|
+
- Images and videos inside an answer are capped at the bubble's width.
|