srcdev-nuxt-components 9.1.55 → 9.1.56
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/settings.json +29 -2
- package/.claude/skills/components/alert-content-inner.md +60 -0
- package/.claude/skills/components/display-dialog.md +80 -0
- package/.claude/skills/components/display-prompt.md +163 -0
- package/.claude/skills/components/display-toast.md +235 -0
- package/.claude/skills/index.md +7 -3
- package/.claude/skills/theming-colour-ramps.md +328 -0
- package/.claude/skills/theming-override-default.md +115 -186
- package/.claude/skills/theming-partial-override.md +88 -75
- package/README.md +166 -0
- package/app/app.config.ts +44 -0
- package/app/assets/styles/setup/01.config/_head.css +3 -3
- package/app/assets/styles/setup/02.colours/_amber.css +12 -10
- package/app/assets/styles/setup/02.colours/_blue.css +10 -9
- package/app/assets/styles/setup/02.colours/_green.css +12 -11
- package/app/assets/styles/setup/02.colours/_orange.css +12 -10
- package/app/assets/styles/setup/02.colours/_red.css +10 -9
- package/app/assets/styles/setup/02.colours/_slate.css +12 -11
- package/app/assets/styles/setup/02.colours/_sunset.css +12 -10
- package/app/assets/styles/setup/02.colours/_theme-params.css +18 -0
- package/app/assets/styles/setup/02.colours/index.css +1 -0
- package/app/assets/styles/setup/03.theming/_default.css +87 -0
- package/app/assets/styles/setup/03.theming/_error.css +14 -0
- package/app/assets/styles/setup/03.theming/_success.css +4 -0
- package/app/assets/styles/setup/03.theming/_theme-slots.css +16 -0
- package/app/assets/styles/setup/03.theming/_warning.css +13 -0
- package/app/assets/styles/setup/03.theming/index.css +6 -4
- package/app/assets/styles/setup/03.theming/theme-ramp.css +19 -0
- package/app/assets/styles/setup/04.elements/forms/00.element-defaults.css +0 -7
- package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
- package/app/assets/styles/setup/index.css +1 -1
- package/app/components/01.atoms/display-dialog/DisplayDialog.vue +74 -24
- package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +148 -14
- package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +3 -3
- package/app/components/01.atoms/prompt/DisplayPrompt.vue +113 -0
- package/app/components/01.atoms/prompt/stories/DisplayPrompt.stories.ts +112 -0
- package/app/components/01.atoms/prompt/tests/DisplayPrompt.spec.ts +205 -0
- package/app/components/01.atoms/toast/DisplayToast.vue +327 -0
- package/app/components/01.atoms/toast/DisplayToastProvider.vue +362 -0
- package/app/components/01.atoms/toast/stories/DisplayToast.stories.ts +195 -0
- package/app/components/01.atoms/toast/stories/DisplayToastProvider.stories.ts +142 -0
- package/app/components/01.atoms/toast/tests/DisplayToast.spec.ts +266 -0
- package/app/components/01.atoms/toast/tests/DisplayToastProvider.spec.ts +256 -0
- package/app/components/02.molecules/action-menu/ActionMenu.vue +8 -1
- package/app/components/02.molecules/action-menu/ActionMenuItemCore.vue +11 -3
- package/app/components/02.molecules/alert-content/AlertContent.vue +67 -0
- package/app/components/02.molecules/alert-content/AlertContentInner.vue +153 -0
- package/app/components/02.molecules/alert-content/stories/AlertContent.stories.ts +131 -0
- package/app/components/02.molecules/alert-content/tests/AlertContent.spec.ts +135 -0
- package/app/components/02.molecules/alert-content/tests/AlertContentInner.spec.ts +135 -0
- package/app/components/02.molecules/alert-masked-content/AlertMaskedContent.vue +78 -0
- package/app/components/02.molecules/alert-masked-content/stories/AlertMaskedContent.stories.ts +132 -0
- package/app/components/02.molecules/alert-masked-content/tests/AlertMaskedContent.spec.ts +149 -0
- package/app/components/05.forms/input-button/InputButtonCore.vue +35 -39
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue +8 -8
- package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue +5 -5
- package/app/components/05.forms/input-copy/InputCopyCore.vue +7 -7
- package/app/components/05.forms/input-number/InputNumberCore.vue +5 -5
- package/app/components/05.forms/input-select/InputSelectCore.vue +6 -6
- package/app/components/05.forms/input-text/InputTextCore.vue +6 -6
- package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +2 -2
- package/app/components/05.forms/input-textarea/InputTextareaCore.vue +5 -5
- package/app/components/05.forms/pending-effect/PendingEffect.vue +60 -60
- package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +10 -10
- package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +4 -4
- package/app/components/display-theme-switch/DisplayThemeSwitch.vue +4 -4
- package/app/components/display-tooltip/DisplayTooltip.vue +4 -4
- package/app/composables/useBodyLock.ts +21 -0
- package/app/composables/useDialogControls.ts +11 -11
- package/app/composables/useToastQueue.ts +39 -0
- package/app/layouts/default.vue +1 -1
- package/app/pages/ui/display-dialog.vue +275 -127
- package/app/pages/ui/display-prompt.vue +255 -52
- package/app/pages/ui/display-toast.vue +278 -299
- package/app/pages/ui/mask-element.vue +25 -3
- package/app/pages/ui/settings.vue +9 -35
- package/app/types/app-config.d.ts +41 -0
- package/app/types/components/display-prompt.d.ts +11 -0
- package/app/types/components/display-toast.d.ts +11 -9
- package/app/types/components/index.ts +2 -0
- package/app/types/components/semantic-theme.d.ts +1 -0
- package/nuxt.config.ts +16 -0
- package/package.json +6 -4
- package/app/assets/styles/setup/03.theming/default/_dark.css +0 -156
- package/app/assets/styles/setup/03.theming/default/_light.css +0 -166
- package/app/assets/styles/setup/03.theming/default/index.css +0 -2
- package/app/assets/styles/setup/03.theming/error/_dark.css +0 -56
- package/app/assets/styles/setup/03.theming/error/_light.css +0 -74
- package/app/assets/styles/setup/03.theming/error/index.css +0 -2
- package/app/assets/styles/setup/03.theming/success/_dark.css +0 -50
- package/app/assets/styles/setup/03.theming/success/_light.css +0 -65
- package/app/assets/styles/setup/03.theming/success/index.css +0 -2
- package/app/assets/styles/setup/03.theming/warning/_dark.css +0 -50
- package/app/assets/styles/setup/03.theming/warning/_light.css +0 -64
- package/app/assets/styles/setup/03.theming/warning/index.css +0 -2
- package/app/components/display-prompt/DisplayPromptCore.vue +0 -228
- package/app/components/display-prompt/variants/DisplayPromptError.vue +0 -53
- package/app/components/display-toast/DisplayToast.vue +0 -447
- package/app/components/display-toast/molecules/DefaultToastContent.vue +0 -163
- package/app/components/display-toast/stories/DisplayToast.stories.ts +0 -380
package/.claude/settings.json
CHANGED
|
@@ -27,10 +27,37 @@
|
|
|
27
27
|
"Bash(git -C /Users/simoncornforth/websites/instepreflexology log --oneline -3)",
|
|
28
28
|
"Bash(git -C /Users/simoncornforth/websites/instepreflexology add package-lock.json .nvmrc)",
|
|
29
29
|
"Bash(git -C /Users/simoncornforth/websites/instepreflexology commit -m ' *)",
|
|
30
|
-
"Bash(git -C /Users/simoncornforth/websites/instepreflexology push)"
|
|
30
|
+
"Bash(git -C /Users/simoncornforth/websites/instepreflexology push)",
|
|
31
|
+
"Bash(node scripts/generate-ramps.mjs)",
|
|
32
|
+
"Bash(sed -i '' 's/var\\(--theme-input-border\\)/var\\(--theme-border\\)/g' app/components/05.forms/input-text/InputTextCore.vue app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue app/components/05.forms/input-textarea/InputTextareaCore.vue app/components/05.forms/input-select/InputSelectCore.vue app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue app/components/05.forms/toggle-switch/ToggleSwitchCore.vue app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue app/components/display-theme-switch/DisplayThemeSwitch.vue app/components/05.forms/input-copy/InputCopyCore.vue app/components/05.forms/input-number/InputNumberCore.vue)",
|
|
33
|
+
"Bash(sed -i '' 's/var\\(--theme-input-outline\\);/transparent;/g' app/components/05.forms/input-text/InputTextCore.vue app/components/05.forms/input-textarea/InputTextareaCore.vue app/components/05.forms/input-select/InputSelectCore.vue app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue app/components/05.forms/toggle-switch/ToggleSwitchCore.vue app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue app/components/display-theme-switch/DisplayThemeSwitch.vue app/components/05.forms/input-number/InputNumberCore.vue)",
|
|
34
|
+
"Bash(sed -i '' 's/var\\(--theme-input-outline-focus\\)/var\\(--theme-border-focus\\)/g' app/components/05.forms/input-text/InputTextCore.vue app/components/05.forms/input-textarea/InputTextareaCore.vue app/components/05.forms/input-select/InputSelectCore.vue app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue app/components/05.forms/toggle-switch/ToggleSwitchCore.vue app/components/05.forms/input-copy/InputCopyCore.vue)",
|
|
35
|
+
"Bash(sed -i '' 's/var\\(--theme-input-outline-hover\\)/var\\(--theme-ring\\)/g' app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue app/components/display-theme-switch/DisplayThemeSwitch.vue)",
|
|
36
|
+
"Bash(sed -i '' 's/var\\(--theme-checkbox-symbol-color\\)/var\\(--theme-text\\)/g' app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue app/components/05.forms/toggle-switch/ToggleSwitchCore.vue)",
|
|
37
|
+
"Bash(sed -i '' 's/var\\(--theme-input-surface-focus\\)/var\\(--theme-surface-subtle\\)/g' /Users/simoncornforth/websites/nuxt-components/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue)",
|
|
38
|
+
"Bash(sed -i '' 's/var\\(--theme-checkbox-label-text-color\\)/var\\(--colour-text-default\\)/g' /Users/simoncornforth/websites/nuxt-components/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue)",
|
|
39
|
+
"Bash(sed -i '' 's/var\\(--theme-button-border\\);/var\\(--theme-border\\);/g; s/var\\(--theme-button-outline\\);/var\\(--theme-ring\\);/g; s/var\\(--theme-button-border-hover\\);/var\\(--theme-surface\\);/g; s/var\\(--theme-button-outline-hover\\);/var\\(--theme-surface\\);/g' /Users/simoncornforth/websites/nuxt-components/app/components/display-tooltip/DisplayTooltip.vue)",
|
|
40
|
+
"Bash(sed -i '' 's/var\\(--theme-input-outline, red\\)/transparent/g' /Users/simoncornforth/websites/nuxt-components/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue)",
|
|
41
|
+
"Bash(xargs ls -la)",
|
|
42
|
+
"Skill(code-review)",
|
|
43
|
+
"Skill(code-review:*)",
|
|
44
|
+
"Bash(cd /Users/simoncornforth/websites/nuxt-components/.vscode && rm srcdev-nuxt3-accordian-component.code-snippets srcdev-nuxt3-carousel-basic-component.code-snippets srcdev-nuxt3-carousel-flip-component.code-snippets srcdev-nuxt3-component-boilerplate.code-snippets srcdev-nuxt3-container-glow-component.code-snippets srcdev-nuxt3-display-banner-component.code-snippets srcdev-nuxt3-display-details-component.code-snippets srcdev-nuxt3-expanding-panel-component.code-snippets srcdev-nuxt3-layout-row.code-snippets srcdev-nuxt3-page-layout.code-snippets srcdev-nuxt3-responsive-header-component.code-snippets srcdev-nuxt3-tabs-component.code-snippets && ls *.code-snippets)",
|
|
45
|
+
"Bash(mv srcdev-nuxt3-dialog-component.code-snippets srcdev-component-dialog.code-snippets)",
|
|
46
|
+
"Bash(mv srcdev-nuxt3-display-prompt-component.code-snippets srcdev-component-display-prompt.code-snippets)",
|
|
47
|
+
"Bash(mv srcdev-nuxt3-display-toast-component.code-snippets srcdev-component-display-toast.code-snippets)",
|
|
48
|
+
"Bash(mv srcdev-nuxt3-pinia-store-setup.code-snippets srcdev-component-pinia-store.code-snippets)",
|
|
49
|
+
"Bash(SRCDEV_STANDALONE=true npx vitest run app/components/01.atoms/display-dialog)",
|
|
50
|
+
"Bash(ls /Users/simoncornforth/websites/nuxt-components/.claude/ && echo \"---\" && cat /Users/simoncornforth/websites/nuxt-components/.gitignore | grep -i \"claude\\\\|memory\\\\|projects\" && echo \"---gitignore done---\" && ls /Users/simoncornforth/.claude/projects/ 2>/dev/null | head -5)",
|
|
51
|
+
"Read(//Users/simoncornforth/.claude/projects/**)",
|
|
52
|
+
"Bash(cp /Users/simoncornforth/websites/nuxt-components/.claude/projects/-Users-simoncornforth-websites-nuxt-components/memory/project_app_config_defaults.md /Users/simoncornforth/.claude/projects/-Users-simoncornforth-websites-nuxt-components/memory/project_app_config_defaults.md)",
|
|
53
|
+
"Bash(rm -rf /Users/simoncornforth/websites/nuxt-components/.claude/projects/)",
|
|
54
|
+
"Bash(SRCDEV_STANDALONE=true npx vitest run app/components/01.atoms/toast)",
|
|
55
|
+
"Bash(SRCDEV_STANDALONE=true npx vitest run app/components/02.molecules/alert-content)",
|
|
56
|
+
"Bash(SRCDEV_STANDALONE=true npx vitest run app/components/01.atoms/prompt)"
|
|
31
57
|
],
|
|
32
58
|
"additionalDirectories": [
|
|
33
|
-
"/Users/simoncornforth/websites/instepreflexology"
|
|
59
|
+
"/Users/simoncornforth/websites/instepreflexology",
|
|
60
|
+
"/Users/simoncornforth/websites/nuxt-components/.vscode"
|
|
34
61
|
]
|
|
35
62
|
}
|
|
36
63
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# AlertContentInner
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Internal molecule used by `AlertContent` and `AlertMaskedContent`, which are in turn used by
|
|
6
|
+
`DisplayToast` and `DisplayPrompt`. Renders the icon, title/body text, and optional dismiss button.
|
|
7
|
+
Because it sits below multiple consumer components, icon customisation here applies everywhere.
|
|
8
|
+
|
|
9
|
+
**Location**: `app/components/02.molecules/alert-content/AlertContentInner.vue`
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Notes |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `theme` | `SemanticTheme` | — | **Required.** Drives the default icon and `data-theme` (set by parent `AlertContent`). |
|
|
16
|
+
| `customIcon` | `string` | `undefined` | Icon name override passed down from the toast/prompt `config.content.customIcon`. |
|
|
17
|
+
| `dismissible` | `boolean` | `false` | Shows the dismiss button when `true`. |
|
|
18
|
+
| `contentId` | `string` | `undefined` | Sets `id` on `.alert-content-body` for `aria-describedby` wiring. |
|
|
19
|
+
| `ariaLive` | `"polite" \| "assertive" \| "off"` | `undefined` | Sets `aria-live` on `.alert-content-body`. |
|
|
20
|
+
|
|
21
|
+
## app.config defaults
|
|
22
|
+
|
|
23
|
+
Icon names — both per-theme and the dismiss button — are configurable globally via `app.config`.
|
|
24
|
+
One change here covers every toast, prompt, and any other component built on `AlertContentInner`.
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// Consumer's app.config.ts
|
|
28
|
+
export default defineAppConfig({
|
|
29
|
+
srcdev: {
|
|
30
|
+
alertContent: {
|
|
31
|
+
icons: {
|
|
32
|
+
info: "heroicons:information-circle",
|
|
33
|
+
success: "heroicons:check-circle",
|
|
34
|
+
warning: "heroicons:exclamation-triangle",
|
|
35
|
+
error: "heroicons:x-circle",
|
|
36
|
+
},
|
|
37
|
+
dismissIcon: "heroicons:x-mark",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Resolution chain: **`customIcon` prop → app.config icons → hardcoded fallback**.
|
|
44
|
+
|
|
45
|
+
The `dismissIcon` slot (`#dismissIcon` on `AlertContent`) always wins over app.config if provided.
|
|
46
|
+
|
|
47
|
+
## Slots
|
|
48
|
+
|
|
49
|
+
| Slot | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `#icon` | Replaces the entire icon region. |
|
|
52
|
+
| `#title` | Title line inside `.alert-content-body`. |
|
|
53
|
+
| `#content` | Body text inside `.alert-content-body`. |
|
|
54
|
+
| `#dismissIcon` | Replaces the dismiss button icon. |
|
|
55
|
+
| `#dismissLabel` | SR-only label for the dismiss button (default: `"Close"`). |
|
|
56
|
+
|
|
57
|
+
## Notes
|
|
58
|
+
|
|
59
|
+
- Do not use `AlertContentInner` directly in pages — use `AlertContent` or `AlertMaskedContent` instead.
|
|
60
|
+
- `AlertMaskedContent` wraps `AlertContentInner` with a different background treatment (SVG glass border).
|
|
@@ -14,11 +14,13 @@ open/close state management.
|
|
|
14
14
|
|---|---|---|---|
|
|
15
15
|
| `dataDialogId` | `string` | — | **Required.** Unique identifier rendered as `data-dialog-id` attribute. |
|
|
16
16
|
| `variant` | `'dialog' \| 'modal' \| 'confirm' \| 'alert' \| 'fullscreen'` | `'dialog'` | Controls panel sizing and ARIA role. |
|
|
17
|
+
| `theme` | `SemanticTheme` | `undefined` | Optional header accent — `data-theme` on `.header` only; adds a coloured bottom border and tints the close icon. |
|
|
17
18
|
| `v-model` | `boolean` | — | Controls open/closed state. |
|
|
18
19
|
| `allowContentScroll` | `boolean` | `false` | Enables independent scroll on `.dialog-content`. |
|
|
19
20
|
| `lockViewport` | `boolean` | `true` | Adds/removes `lock` class on `<body>` on mount/close. |
|
|
20
21
|
| `justifyDialog` | `'start' \| 'center' \| 'end'` | `'center'` | Horizontal position of panel within overlay. |
|
|
21
22
|
| `alignDialog` | `'start' \| 'center' \| 'end'` | `'center'` | Vertical position of panel within overlay. |
|
|
23
|
+
| `closeIcon` | `string` | app.config | Icon name for the header close button. Override per-instance or set globally via `app.config`. |
|
|
22
24
|
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes applied to the root `<dialog>` element. |
|
|
23
25
|
|
|
24
26
|
## Slots
|
|
@@ -104,6 +106,28 @@ are both disabled — the user must act via the footer buttons.
|
|
|
104
106
|
</DisplayDialog>
|
|
105
107
|
```
|
|
106
108
|
|
|
109
|
+
## app.config defaults
|
|
110
|
+
|
|
111
|
+
All props except `dataDialogId` and `styleClassPassthrough` can be set globally via `app.config`.
|
|
112
|
+
The resolution chain is: **explicit prop → app.config → hardcoded fallback**.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
// app.config.ts in the consumer app
|
|
116
|
+
export default defineAppConfig({
|
|
117
|
+
srcdev: {
|
|
118
|
+
displayDialog: {
|
|
119
|
+
variant: "modal",
|
|
120
|
+
alignDialog: "end",
|
|
121
|
+
lockViewport: true,
|
|
122
|
+
closeIcon: "heroicons:x-mark",
|
|
123
|
+
theme: "info",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Per-instance props always win — app.config only fills in when a prop is absent.
|
|
130
|
+
|
|
107
131
|
## CSS token API
|
|
108
132
|
|
|
109
133
|
See `CONSUMER-STYLING.md` in the component folder for the full token reference. Prefer global
|
|
@@ -119,6 +143,62 @@ CSS over per-instance overrides — dialogs are site-wide UI:
|
|
|
119
143
|
}
|
|
120
144
|
```
|
|
121
145
|
|
|
146
|
+
## Nested dialogs
|
|
147
|
+
|
|
148
|
+
When a dialog needs to launch its own sub-dialog (e.g. "Discard changes?" before closing an edit
|
|
149
|
+
form), the cleanest approach is to call `useDialogControls` **inside the dialog component itself**.
|
|
150
|
+
The sub-dialog is entirely self-contained — the parent page doesn't need to know about it.
|
|
151
|
+
|
|
152
|
+
```vue
|
|
153
|
+
<!-- EditProfileDialog.vue -->
|
|
154
|
+
<script setup lang="ts">
|
|
155
|
+
const emit = defineEmits<{ close: [] }>();
|
|
156
|
+
|
|
157
|
+
const { dialogsConfig, openDialog, closeDialog } = useDialogControls({
|
|
158
|
+
confirmDiscard: {
|
|
159
|
+
onConfirm: () => emit("close"),
|
|
160
|
+
onCancel: () => {},
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const handleClose = () => {
|
|
165
|
+
if (hasUnsavedChanges.value) {
|
|
166
|
+
openDialog("confirmDiscard");
|
|
167
|
+
} else {
|
|
168
|
+
emit("close");
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
</script>
|
|
172
|
+
|
|
173
|
+
<template>
|
|
174
|
+
<!-- main dialog content, close button calls handleClose() -->
|
|
175
|
+
|
|
176
|
+
<!-- sub-dialog rendered inside the same component -->
|
|
177
|
+
<DisplayDialog
|
|
178
|
+
v-if="dialogsConfig['confirmDiscard']"
|
|
179
|
+
v-model="dialogsConfig['confirmDiscard']"
|
|
180
|
+
variant="confirm"
|
|
181
|
+
theme="warning"
|
|
182
|
+
data-dialog-id="confirmDiscard"
|
|
183
|
+
>
|
|
184
|
+
<template #dialogTitle><p>Discard changes?</p></template>
|
|
185
|
+
<template #dialogContent><p>Your unsaved changes will be lost.</p></template>
|
|
186
|
+
<template #actionButtonLeft>
|
|
187
|
+
<button @click="closeDialog('confirmDiscard', 'cancel')">Keep editing</button>
|
|
188
|
+
</template>
|
|
189
|
+
<template #actionButtonRight>
|
|
190
|
+
<button @click="closeDialog('confirmDiscard', 'confirm')">Discard</button>
|
|
191
|
+
</template>
|
|
192
|
+
</DisplayDialog>
|
|
193
|
+
</template>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Both dialogs are open simultaneously — native `<dialog>` stacking order ensures the confirm
|
|
197
|
+
renders on top. The confirm resolves first; its `onConfirm` callback triggers the parent close.
|
|
198
|
+
|
|
199
|
+
**Avoid** registering the sub-dialog on the page level — that couples the page to the dialog's
|
|
200
|
+
internal concern and leaks implementation detail upward.
|
|
201
|
+
|
|
122
202
|
## Notes
|
|
123
203
|
|
|
124
204
|
- Always use `v-if="dialogsConfig['id']"` (not `v-show`) — `DisplayDialog` runs body-lock logic
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# DisplayPrompt
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`DisplayPrompt` is an inline notification banner with a themed icon, title, optional content, and
|
|
6
|
+
an optional dismiss button. It collapses in-place via CSS grid animation rather than removing from
|
|
7
|
+
the DOM. Dismiss can be controlled locally (closes itself) or by a parent via `v-model`.
|
|
8
|
+
|
|
9
|
+
**Location**: `app/components/01.atoms/prompt/DisplayPrompt.vue`
|
|
10
|
+
**Types**: `~/types/components` — `DisplayPromptTheme`, `SemanticTheme`
|
|
11
|
+
|
|
12
|
+
## Props
|
|
13
|
+
|
|
14
|
+
| Prop | Type | Default | Notes |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| `theme` | `SemanticTheme` | `"info"` | `"info" \| "success" \| "warning" \| "error"` |
|
|
17
|
+
| `dismissible` | `boolean` | `false` | Shows a close button. |
|
|
18
|
+
| `useAutoFocus` | `boolean` | `false` | Focuses the prompt root element on mount. |
|
|
19
|
+
| `masked` | `boolean` | `false` | SVG glass border — swaps `AlertContent` for `AlertMaskedContent`. |
|
|
20
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes on the inner wrapper. Supported modifier: `"outlined"`. |
|
|
21
|
+
| `v-model` | `boolean` | `false` | Optional parent control — see dismiss behaviour below. |
|
|
22
|
+
|
|
23
|
+
## Slots
|
|
24
|
+
|
|
25
|
+
| Slot | Description |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `#title` | **Required in practice.** Bold heading text. Always rendered (even when empty). |
|
|
28
|
+
| `#content` | Body text below the title. The `<p>` element is omitted when this slot is empty. |
|
|
29
|
+
| `#customDecoratorIcon` | Replaces the default theme icon. |
|
|
30
|
+
| `#customCloseIcon` | Replaces the default × close icon inside the dismiss button. |
|
|
31
|
+
| `#customTitle` | Screen-reader label for the dismiss button (default: `"Close this prompt"`). |
|
|
32
|
+
|
|
33
|
+
## Themes
|
|
34
|
+
|
|
35
|
+
| Theme | Default icon |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `"info"` | `akar-icons:info` |
|
|
38
|
+
| `"success"` | `akar-icons:check` |
|
|
39
|
+
| `"warning"` | `akar-icons:circle-alert` |
|
|
40
|
+
| `"error"` | `akar-icons:circle-alert` |
|
|
41
|
+
|
|
42
|
+
`data-theme` is set on `.display-prompt-wrapper`, activating the CSS palette (`--theme-accent`,
|
|
43
|
+
`--theme-text`, `--theme-border`, `--theme-ring`, etc.). The wrapper's left-edge accent uses
|
|
44
|
+
`--theme-accent` (step 5/4) — not `--theme-surface` — so it stays visually distinct from buttons.
|
|
45
|
+
|
|
46
|
+
## Dismiss behaviour
|
|
47
|
+
|
|
48
|
+
Two modes depending on whether `v-model` is bound:
|
|
49
|
+
|
|
50
|
+
| Scenario | What happens on close |
|
|
51
|
+
|---|---|
|
|
52
|
+
| No `v-model` (or `v-model="false"`) | Sets internal `componentOpen = false` → `.closed` class → collapses via CSS |
|
|
53
|
+
| `v-model="true"` | Emits `update:modelValue = false`; internal state unchanged — parent controls visibility |
|
|
54
|
+
|
|
55
|
+
The `.closed` class triggers a CSS grid row animation (`grid-template-rows: 1fr → 0fr`) with
|
|
56
|
+
`opacity: 0` and `pointer-events: none`.
|
|
57
|
+
|
|
58
|
+
## app.config defaults
|
|
59
|
+
|
|
60
|
+
All props except `styleClassPassthrough` can be set globally so every prompt in the app inherits
|
|
61
|
+
the same defaults without repeating them at each usage site.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// Consumer's app.config.ts
|
|
65
|
+
export default defineAppConfig({
|
|
66
|
+
srcdev: {
|
|
67
|
+
displayPrompt: {
|
|
68
|
+
theme: "info",
|
|
69
|
+
dismissible: true,
|
|
70
|
+
masked: false,
|
|
71
|
+
useAutoFocus: false,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Resolution chain: **explicit prop → app.config → hardcoded fallback**.
|
|
78
|
+
|
|
79
|
+
## Basic usage
|
|
80
|
+
|
|
81
|
+
```vue
|
|
82
|
+
<DisplayPrompt theme="info">
|
|
83
|
+
<template #title>Your session will expire soon.</template>
|
|
84
|
+
<template #content>Save your work to avoid losing changes.</template>
|
|
85
|
+
</DisplayPrompt>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Dismissible prompt
|
|
89
|
+
|
|
90
|
+
```vue
|
|
91
|
+
<DisplayPrompt theme="warning" :dismissible="true">
|
|
92
|
+
<template #title>Action required</template>
|
|
93
|
+
<template #content>Please verify your email address.</template>
|
|
94
|
+
</DisplayPrompt>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Parent-controlled dismiss (v-model)
|
|
98
|
+
|
|
99
|
+
Use when the parent needs to react to dismiss (e.g. save state, conditionally re-show):
|
|
100
|
+
|
|
101
|
+
```vue
|
|
102
|
+
<script setup lang="ts">
|
|
103
|
+
const showPrompt = ref(true)
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<template>
|
|
107
|
+
<DisplayPrompt
|
|
108
|
+
v-model="showPrompt"
|
|
109
|
+
theme="success"
|
|
110
|
+
:dismissible="true"
|
|
111
|
+
>
|
|
112
|
+
<template #title>Profile updated.</template>
|
|
113
|
+
</DisplayPrompt>
|
|
114
|
+
</template>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## `styleClassPassthrough` modifiers
|
|
118
|
+
|
|
119
|
+
| Class | Effect |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `"outlined"` | Adds `1px solid var(--theme-border)` border to the wrapper |
|
|
122
|
+
|
|
123
|
+
Apply via prop:
|
|
124
|
+
|
|
125
|
+
```vue
|
|
126
|
+
<DisplayPrompt :style-class-passthrough="['outlined']" theme="error">
|
|
127
|
+
<template #title>Something went wrong.</template>
|
|
128
|
+
</DisplayPrompt>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## CSS token override
|
|
132
|
+
|
|
133
|
+
Scope overrides using your page or section wrapper class — no `:deep()` needed:
|
|
134
|
+
|
|
135
|
+
```css
|
|
136
|
+
.my-section .display-prompt-wrapper {
|
|
137
|
+
--theme-accent: oklch(60% 0.18 140); /* left-edge accent strip */
|
|
138
|
+
border-radius: 0.8rem;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Masked variant
|
|
143
|
+
|
|
144
|
+
Setting `:masked="true"` swaps `AlertContent` for `AlertMaskedContent`, giving the prompt an SVG-based
|
|
145
|
+
border and a semi-transparent background so content behind it is faintly visible. The inner layout is
|
|
146
|
+
identical — all the same slots apply. Place the prompt over a coloured or image background for the
|
|
147
|
+
glass effect to be visible.
|
|
148
|
+
|
|
149
|
+
```vue
|
|
150
|
+
<DisplayPrompt theme="info" :masked="true">
|
|
151
|
+
<template #title>Glass prompt</template>
|
|
152
|
+
<template #content>Semi-transparent, backed by AlertMaskedContent.</template>
|
|
153
|
+
</DisplayPrompt>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Notes
|
|
157
|
+
|
|
158
|
+
- `DisplayPromptTheme` is an alias for `SemanticTheme` (`"info" | "success" | "warning" | "error"`).
|
|
159
|
+
- The root element always has `tabindex="0"` — it is focusable whether or not `dismissible` is set.
|
|
160
|
+
- `useAutoFocus` focuses the root element on mount (useful when injecting a prompt in response to a
|
|
161
|
+
user action that has already moved focus elsewhere).
|
|
162
|
+
- The `#title` slot renders unconditionally — an empty title `<p>` will still appear. Always
|
|
163
|
+
provide meaningful content in `#title`.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# DisplayToast / DisplayToastProvider
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Two patterns are available depending on the use case:
|
|
6
|
+
|
|
7
|
+
| Pattern | Component | When to use |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| **Standalone** | `DisplayToast` | One-off toast tied to a specific UI action; no queueing needed |
|
|
10
|
+
| **App-wide queue** | `DisplayToastProvider` + `useToastQueue` | Multiple toasts across the app, stacking, queue management |
|
|
11
|
+
|
|
12
|
+
**Locations**:
|
|
13
|
+
|
|
14
|
+
- `app/components/01.atoms/toast/DisplayToast.vue`
|
|
15
|
+
- `app/components/01.atoms/toast/DisplayToastProvider.vue`
|
|
16
|
+
- `app/composables/useToastQueue.ts`
|
|
17
|
+
- `app/components/01.atoms/toast/molecules/DefaultToastContent.vue`
|
|
18
|
+
|
|
19
|
+
**Types**: `~/types/components` — `DisplayToastConfig`, `DisplayToastTheme`, `ToastQueueEntry`, `ToastQueueStatus`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Pattern 1 — Standalone (`DisplayToast`)
|
|
24
|
+
|
|
25
|
+
Triggered via `v-model`. Each instance manages its own visibility and position.
|
|
26
|
+
|
|
27
|
+
### Props
|
|
28
|
+
|
|
29
|
+
| Prop | Type | Default | Notes |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| `v-model` | `boolean` | `false` | `true` shows; `false` hides. |
|
|
32
|
+
| `config` | `DisplayToastConfig` | see below | All sub-keys optional. |
|
|
33
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra classes on the root element. |
|
|
34
|
+
|
|
35
|
+
### Config shape
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
interface DisplayToastConfig {
|
|
39
|
+
appearance?: {
|
|
40
|
+
theme?: SemanticTheme // "info" | "success" | "warning" | "error" — default: "info"
|
|
41
|
+
position?: "top" | "bottom" // default: "top"
|
|
42
|
+
alignment?: "left" | "center" | "right" // default: "right"
|
|
43
|
+
fullWidth?: boolean // default: false — overrides alignment
|
|
44
|
+
masked?: boolean // SVG glass border — semi-transparent background — default: false
|
|
45
|
+
}
|
|
46
|
+
behavior?: {
|
|
47
|
+
autoDismiss?: boolean // default: true
|
|
48
|
+
duration?: number // ms before auto-dismiss — default: 5000
|
|
49
|
+
revealDuration?: number // animation duration ms — default: 550
|
|
50
|
+
returnFocusTo?: HTMLElement | ComponentPublicInstance | null
|
|
51
|
+
}
|
|
52
|
+
content?: {
|
|
53
|
+
text?: string // simple message (used when no title/description)
|
|
54
|
+
title?: string // bold title line
|
|
55
|
+
description?: string // smaller description line
|
|
56
|
+
customIcon?: string // icon name override (e.g. "akar-icons:check-box")
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### app.config defaults
|
|
62
|
+
|
|
63
|
+
`appearance` and `behavior` keys (not `content` — that's per-instance) can be set globally so
|
|
64
|
+
every toast in the app inherits the same defaults without repeating them in every `config` prop.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// Consumer's app.config.ts
|
|
68
|
+
export default defineAppConfig({
|
|
69
|
+
srcdev: {
|
|
70
|
+
displayToast: {
|
|
71
|
+
appearance: { theme: "success", position: "bottom", alignment: "left" },
|
|
72
|
+
behavior: { autoDismiss: true, duration: 4000 },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Resolution chain: **`config` prop → app.config → hardcoded fallback**.
|
|
79
|
+
|
|
80
|
+
### Slots
|
|
81
|
+
|
|
82
|
+
| Slot | Description |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `default` | Replaces `DefaultToastContent` entirely. `has-theme`, `tabindex`, and `aria-describedby` are omitted — accessibility is the caller's responsibility. |
|
|
85
|
+
| `#customToastIcon` | Replaces the default theme icon. |
|
|
86
|
+
| `#title` | Replaces `config.content.title`. Do not provide both slot and config value. |
|
|
87
|
+
| `#description` | Replaces `config.content.description`. Do not provide both slot and config value. |
|
|
88
|
+
|
|
89
|
+
### Basic usage
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<script setup lang="ts">
|
|
93
|
+
const toastVisible = ref(false)
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<template>
|
|
97
|
+
<button @click="toastVisible = true">Save</button>
|
|
98
|
+
|
|
99
|
+
<DisplayToast
|
|
100
|
+
v-model="toastVisible"
|
|
101
|
+
:config="{
|
|
102
|
+
appearance: { theme: 'success' },
|
|
103
|
+
behavior: { autoDismiss: true, duration: 4000 },
|
|
104
|
+
content: { text: 'Changes saved.' },
|
|
105
|
+
}"
|
|
106
|
+
/>
|
|
107
|
+
</template>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Notes
|
|
111
|
+
|
|
112
|
+
- `onBeforeRouteLeave` dismisses the toast on navigation. This emits a Vue Router warning in Vitest (no active route record) — harmless.
|
|
113
|
+
- `returnFocusTo` accepts an `HTMLElement` or a component instance with `$el`.
|
|
114
|
+
- The toast uses `<Teleport to="body">`. In tests, query `document.querySelector(".display-toast")` not `wrapper.find()`.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Pattern 2 — App-wide queue (`DisplayToastProvider` + `useToastQueue`)
|
|
119
|
+
|
|
120
|
+
Place `DisplayToastProvider` once in the app layout. Trigger toasts from anywhere using `useToastQueue`. The provider promotes pending entries to visible up to `maxVisible`, manages timers, and handles stacked FLIP animations.
|
|
121
|
+
|
|
122
|
+
### Setup — layout
|
|
123
|
+
|
|
124
|
+
```vue
|
|
125
|
+
<!-- layouts/default.vue -->
|
|
126
|
+
<template>
|
|
127
|
+
<div>
|
|
128
|
+
<slot />
|
|
129
|
+
<DisplayToastProvider position="top" alignment="right" :max-visible="1" />
|
|
130
|
+
</div>
|
|
131
|
+
</template>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Only one `DisplayToastProvider` should be mounted at a time. It uses `<Teleport to="body">` so its placement in the layout tree does not affect visual output.
|
|
135
|
+
|
|
136
|
+
### `DisplayToastProvider` props
|
|
137
|
+
|
|
138
|
+
| Prop | Type | Default | Notes |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| `position` | `"top" \| "bottom"` | `"top"` | Vertical screen edge |
|
|
141
|
+
| `alignment` | `"left" \| "center" \| "right"` | `"right"` | Horizontal alignment (ignored when `fullWidth`) |
|
|
142
|
+
| `fullWidth` | `boolean` | `false` | Toast spans the full viewport width |
|
|
143
|
+
| `maxVisible` | `number` | `1` | Max toasts visible simultaneously; rest queue as pending |
|
|
144
|
+
|
|
145
|
+
### `useToastQueue` API
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const { show, dismiss, clear, queue } = useToastQueue()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
| Method | Signature | Notes |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `show(config)` | `(config: DisplayToastConfig) => string` | Adds a toast to the queue; returns its ID |
|
|
154
|
+
| `dismiss(id)` | `(id: string) => void` | Removes a specific toast by ID |
|
|
155
|
+
| `clear()` | `() => void` | Flushes all pending and visible toasts |
|
|
156
|
+
| `queue` | `Readonly<Ref<ToastQueueEntry[]>>` | Reactive read-only queue state |
|
|
157
|
+
|
|
158
|
+
The composable uses a **module-level singleton** — state is shared across all callers without Pinia. Safe for client-only ephemeral UI state.
|
|
159
|
+
|
|
160
|
+
> **Internal API**: `DisplayToastProvider` uses `useToastQueueProvider()` (a separate export from the same file) which additionally exposes `promote`. Do not call `useToastQueueProvider` from consuming app code — manually promoting without a timer puts the queue into an inconsistent state.
|
|
161
|
+
|
|
162
|
+
### Triggering toasts
|
|
163
|
+
|
|
164
|
+
```vue
|
|
165
|
+
<script setup lang="ts">
|
|
166
|
+
const { show } = useToastQueue()
|
|
167
|
+
|
|
168
|
+
const onSave = async () => {
|
|
169
|
+
try {
|
|
170
|
+
await save()
|
|
171
|
+
show({
|
|
172
|
+
appearance: { theme: 'success' },
|
|
173
|
+
behavior: { autoDismiss: true, duration: 4000 },
|
|
174
|
+
content: { title: 'Saved', description: 'Your changes have been saved.' },
|
|
175
|
+
})
|
|
176
|
+
} catch {
|
|
177
|
+
show({
|
|
178
|
+
appearance: { theme: 'error' },
|
|
179
|
+
behavior: { autoDismiss: false },
|
|
180
|
+
content: { title: 'Save failed', description: 'Check your connection and try again.' },
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
</script>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Stacking (`maxVisible > 1`)
|
|
188
|
+
|
|
189
|
+
```vue
|
|
190
|
+
<DisplayToastProvider :max-visible="3" position="top" alignment="right" />
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
With `maxVisible: 3` and 5 toasts triggered:
|
|
194
|
+
|
|
195
|
+
- Toasts 1–3 are visible immediately
|
|
196
|
+
- Toasts 4–5 queue as `pending`
|
|
197
|
+
- When toast 1 is dismissed, toast 4 is promoted and animates in
|
|
198
|
+
|
|
199
|
+
Stacked dismissals use a FLIP animation — remaining toasts slide smoothly to fill the gap rather than snapping.
|
|
200
|
+
|
|
201
|
+
### Themes and ARIA
|
|
202
|
+
|
|
203
|
+
| Theme | ARIA role | aria-live |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `"info"` | `status` | `polite` |
|
|
206
|
+
| `"success"` | `status` | `polite` |
|
|
207
|
+
| `"warning"` | `alert` | `assertive` |
|
|
208
|
+
| `"error"` | `alert` | `assertive` |
|
|
209
|
+
|
|
210
|
+
### CSS / styling
|
|
211
|
+
|
|
212
|
+
Override tokens via an unscoped style block scoped to a page or layout class:
|
|
213
|
+
|
|
214
|
+
```css
|
|
215
|
+
.my-page .display-toast-provider-item {
|
|
216
|
+
--theme-surface: oklch(15% 0 0);
|
|
217
|
+
--theme-text: oklch(95% 0 0);
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Masked variant
|
|
222
|
+
|
|
223
|
+
Setting `appearance.masked: true` swaps `AlertContent` for `AlertMaskedContent`, which uses an SVG-based border and a semi-transparent background (`rgba(0,0,0,0.3)`) so page content is faintly visible beneath the toast.
|
|
224
|
+
|
|
225
|
+
The SVG border shape matches the standard toast exactly (8px left radius, 4px right, 6px accent-colour left bar via `--theme-accent`). Override any dimension or colour via a `maskConfig` prop if using `AlertMaskedContent` standalone.
|
|
226
|
+
|
|
227
|
+
The inner content layout is handled by the shared `AlertContentInner` molecule — both variants reuse it. `AlertMaskedContent` overrides `--_alert-content-inner-bg: transparent` so the glass effect shows through.
|
|
228
|
+
|
|
229
|
+
### Provider notes
|
|
230
|
+
|
|
231
|
+
- `useToastQueue` state persists across route changes — no `onBeforeRouteLeave` cleanup needed.
|
|
232
|
+
- `crypto.randomUUID()` generates toast IDs (`toast-<uuid>`). IDs are returned by `show()` for targeted `dismiss(id)` calls.
|
|
233
|
+
- In tests, query via `document.querySelector(".display-toast-provider-item")` — the Teleport renders outside the component wrapper.
|
|
234
|
+
- The progress bar (`.display-toast-provider-progress`) is only rendered when `autoDismiss: true`.
|
|
235
|
+
- Dismissal can be triggered by: close button click, Escape key (when the toast item has focus), `dismiss(id)`, auto-dismiss timer, or `clear()`.
|
package/.claude/skills/index.md
CHANGED
|
@@ -27,8 +27,9 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
27
27
|
├── testing-add-unit-test.md — create a Vitest unit test with snapshots
|
|
28
28
|
├── testing-add-playwright.md — create a Playwright visual regression test
|
|
29
29
|
├── setup-postinstall.md — automate nuxt prepare + Claude skills copy via postinstall so neither is forgotten after npm install
|
|
30
|
-
├── theming-
|
|
31
|
-
├── theming-
|
|
30
|
+
├── theming-colour-ramps.md — parametric oklch ramp system: formula, named palettes, semantic slots, generator, consumer setup
|
|
31
|
+
├── theming-override-default.md — replace the entire default theme with a custom palette (set --theme-hue/--theme-chroma)
|
|
32
|
+
├── theming-partial-override.md — override a specific token category (palette, buttons, inputs) without a full theme replacement
|
|
32
33
|
├── colour-scheme-disable.md — disable light/dark scheme support in a consumer app
|
|
33
34
|
├── component-dynamic-slots.md — named dynamic slots ($slots iteration) vs indexed dynamic slots (itemCount pattern)
|
|
34
35
|
├── component-local-style-override.md — styleClassPassthrough + scoped style block for per-usage visual customisation
|
|
@@ -55,6 +56,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
55
56
|
├── composable-anchor-scroll.md — useAnchorScroll: smooth anchor scrolling with reduced-motion support, dynamic offset, and TabNavigation integration
|
|
56
57
|
├── composable-tooltips-guide.md — useTooltipsGuide: sequential popover guide with auto-start, dismiss-to-advance, manual controls
|
|
57
58
|
└── components/
|
|
59
|
+
├── alert-content-inner.md — AlertContentInner: shared icon/body/dismiss molecule under AlertContent + AlertMaskedContent; app.config icon map (alertContent.icons + dismissIcon) covers all consumers
|
|
58
60
|
├── accordian-core.md — AccordianCore indexed dynamic slots (accordian-{n}-summary/icon/content), exclusive-open grouping
|
|
59
61
|
├── eyebrow-text.md — EyebrowText props, usage patterns, styling
|
|
60
62
|
├── hero-text.md — HeroText props, usage patterns, styling
|
|
@@ -90,7 +92,9 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
90
92
|
├── display-chip.md — DisplayChip: status indicator chip overlay, CSS trig positioning, circle/square shapes, status colours, icon/label content
|
|
91
93
|
├── display-pill.md — DisplayPill: pill/badge label with icon slot, 6 variants, 3 sizes, reversible order, full CSS token API for border/outline/colour
|
|
92
94
|
├── carousel-flip.md — CarouselFlip: FLIP-animated carousel, carouselDataIds slot API, buttonLayout variants (sides/controls-flanking/controls-grouped-right/overlay), CSS tokens
|
|
93
|
-
|
|
95
|
+
├── samaritan-prompt-mixed.md — SamaritanPromptMixed: animated text prompt, typewriter/word-pulse effects, MessageConfig API, aria-live accessibility, CSS tokens
|
|
96
|
+
├── display-toast.md — DisplayToast (standalone v-model) + DisplayToastProvider + useToastQueue (app-wide queue): stacking, FLIP dismiss, maxVisible, SemanticTheme × 4, masked SVG glass variant
|
|
97
|
+
└── display-prompt.md — DisplayPrompt: inline notification banner, SemanticTheme × 4, local vs parent-controlled dismiss, outlined modifier, CSS token override
|
|
94
98
|
```
|
|
95
99
|
|
|
96
100
|
## Skill file template
|