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.
Files changed (100) hide show
  1. package/.claude/settings.json +29 -2
  2. package/.claude/skills/components/alert-content-inner.md +60 -0
  3. package/.claude/skills/components/display-dialog.md +80 -0
  4. package/.claude/skills/components/display-prompt.md +163 -0
  5. package/.claude/skills/components/display-toast.md +235 -0
  6. package/.claude/skills/index.md +7 -3
  7. package/.claude/skills/theming-colour-ramps.md +328 -0
  8. package/.claude/skills/theming-override-default.md +115 -186
  9. package/.claude/skills/theming-partial-override.md +88 -75
  10. package/README.md +166 -0
  11. package/app/app.config.ts +44 -0
  12. package/app/assets/styles/setup/01.config/_head.css +3 -3
  13. package/app/assets/styles/setup/02.colours/_amber.css +12 -10
  14. package/app/assets/styles/setup/02.colours/_blue.css +10 -9
  15. package/app/assets/styles/setup/02.colours/_green.css +12 -11
  16. package/app/assets/styles/setup/02.colours/_orange.css +12 -10
  17. package/app/assets/styles/setup/02.colours/_red.css +10 -9
  18. package/app/assets/styles/setup/02.colours/_slate.css +12 -11
  19. package/app/assets/styles/setup/02.colours/_sunset.css +12 -10
  20. package/app/assets/styles/setup/02.colours/_theme-params.css +18 -0
  21. package/app/assets/styles/setup/02.colours/index.css +1 -0
  22. package/app/assets/styles/setup/03.theming/_default.css +87 -0
  23. package/app/assets/styles/setup/03.theming/_error.css +14 -0
  24. package/app/assets/styles/setup/03.theming/_success.css +4 -0
  25. package/app/assets/styles/setup/03.theming/_theme-slots.css +16 -0
  26. package/app/assets/styles/setup/03.theming/_warning.css +13 -0
  27. package/app/assets/styles/setup/03.theming/index.css +6 -4
  28. package/app/assets/styles/setup/03.theming/theme-ramp.css +19 -0
  29. package/app/assets/styles/setup/04.elements/forms/00.element-defaults.css +0 -7
  30. package/app/assets/styles/setup/04.elements/forms/06.button-geometry.css +1 -1
  31. package/app/assets/styles/setup/index.css +1 -1
  32. package/app/components/01.atoms/display-dialog/DisplayDialog.vue +74 -24
  33. package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +148 -14
  34. package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +3 -3
  35. package/app/components/01.atoms/prompt/DisplayPrompt.vue +113 -0
  36. package/app/components/01.atoms/prompt/stories/DisplayPrompt.stories.ts +112 -0
  37. package/app/components/01.atoms/prompt/tests/DisplayPrompt.spec.ts +205 -0
  38. package/app/components/01.atoms/toast/DisplayToast.vue +327 -0
  39. package/app/components/01.atoms/toast/DisplayToastProvider.vue +362 -0
  40. package/app/components/01.atoms/toast/stories/DisplayToast.stories.ts +195 -0
  41. package/app/components/01.atoms/toast/stories/DisplayToastProvider.stories.ts +142 -0
  42. package/app/components/01.atoms/toast/tests/DisplayToast.spec.ts +266 -0
  43. package/app/components/01.atoms/toast/tests/DisplayToastProvider.spec.ts +256 -0
  44. package/app/components/02.molecules/action-menu/ActionMenu.vue +8 -1
  45. package/app/components/02.molecules/action-menu/ActionMenuItemCore.vue +11 -3
  46. package/app/components/02.molecules/alert-content/AlertContent.vue +67 -0
  47. package/app/components/02.molecules/alert-content/AlertContentInner.vue +153 -0
  48. package/app/components/02.molecules/alert-content/stories/AlertContent.stories.ts +131 -0
  49. package/app/components/02.molecules/alert-content/tests/AlertContent.spec.ts +135 -0
  50. package/app/components/02.molecules/alert-content/tests/AlertContentInner.spec.ts +135 -0
  51. package/app/components/02.molecules/alert-masked-content/AlertMaskedContent.vue +78 -0
  52. package/app/components/02.molecules/alert-masked-content/stories/AlertMaskedContent.stories.ts +132 -0
  53. package/app/components/02.molecules/alert-masked-content/tests/AlertMaskedContent.spec.ts +149 -0
  54. package/app/components/05.forms/input-button/InputButtonCore.vue +35 -39
  55. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioButton.vue +8 -8
  56. package/app/components/05.forms/input-checkbox-radio/InputCheckboxRadioCore.vue +5 -5
  57. package/app/components/05.forms/input-copy/InputCopyCore.vue +7 -7
  58. package/app/components/05.forms/input-number/InputNumberCore.vue +5 -5
  59. package/app/components/05.forms/input-select/InputSelectCore.vue +6 -6
  60. package/app/components/05.forms/input-text/InputTextCore.vue +6 -6
  61. package/app/components/05.forms/input-text/variants/InputTextAsNumberWithLabel.vue +2 -2
  62. package/app/components/05.forms/input-textarea/InputTextareaCore.vue +5 -5
  63. package/app/components/05.forms/pending-effect/PendingEffect.vue +60 -60
  64. package/app/components/05.forms/toggle-switch/ToggleSwitchCore.vue +10 -10
  65. package/app/components/05.forms/triple-toggle-switch/TripleToggleSwitchCore.vue +4 -4
  66. package/app/components/display-theme-switch/DisplayThemeSwitch.vue +4 -4
  67. package/app/components/display-tooltip/DisplayTooltip.vue +4 -4
  68. package/app/composables/useBodyLock.ts +21 -0
  69. package/app/composables/useDialogControls.ts +11 -11
  70. package/app/composables/useToastQueue.ts +39 -0
  71. package/app/layouts/default.vue +1 -1
  72. package/app/pages/ui/display-dialog.vue +275 -127
  73. package/app/pages/ui/display-prompt.vue +255 -52
  74. package/app/pages/ui/display-toast.vue +278 -299
  75. package/app/pages/ui/mask-element.vue +25 -3
  76. package/app/pages/ui/settings.vue +9 -35
  77. package/app/types/app-config.d.ts +41 -0
  78. package/app/types/components/display-prompt.d.ts +11 -0
  79. package/app/types/components/display-toast.d.ts +11 -9
  80. package/app/types/components/index.ts +2 -0
  81. package/app/types/components/semantic-theme.d.ts +1 -0
  82. package/nuxt.config.ts +16 -0
  83. package/package.json +6 -4
  84. package/app/assets/styles/setup/03.theming/default/_dark.css +0 -156
  85. package/app/assets/styles/setup/03.theming/default/_light.css +0 -166
  86. package/app/assets/styles/setup/03.theming/default/index.css +0 -2
  87. package/app/assets/styles/setup/03.theming/error/_dark.css +0 -56
  88. package/app/assets/styles/setup/03.theming/error/_light.css +0 -74
  89. package/app/assets/styles/setup/03.theming/error/index.css +0 -2
  90. package/app/assets/styles/setup/03.theming/success/_dark.css +0 -50
  91. package/app/assets/styles/setup/03.theming/success/_light.css +0 -65
  92. package/app/assets/styles/setup/03.theming/success/index.css +0 -2
  93. package/app/assets/styles/setup/03.theming/warning/_dark.css +0 -50
  94. package/app/assets/styles/setup/03.theming/warning/_light.css +0 -64
  95. package/app/assets/styles/setup/03.theming/warning/index.css +0 -2
  96. package/app/components/display-prompt/DisplayPromptCore.vue +0 -228
  97. package/app/components/display-prompt/variants/DisplayPromptError.vue +0 -53
  98. package/app/components/display-toast/DisplayToast.vue +0 -447
  99. package/app/components/display-toast/molecules/DefaultToastContent.vue +0 -163
  100. package/app/components/display-toast/stories/DisplayToast.stories.ts +0 -380
@@ -0,0 +1,132 @@
1
+ import type { Meta, StoryObj } from "@nuxtjs/storybook";
2
+ import AlertMaskedContent from "../AlertMaskedContent.vue";
3
+
4
+ const meta: Meta<typeof AlertMaskedContent> = {
5
+ title: "Molecules/AlertMaskedContent",
6
+ component: AlertMaskedContent,
7
+ argTypes: {
8
+ theme: {
9
+ control: { type: "inline-radio" },
10
+ options: ["info", "success", "warning", "error"],
11
+ description: "Semantic theme — controls the accent colour and default icon",
12
+ table: { category: "Appearance" },
13
+ },
14
+ customIcon: {
15
+ control: "text",
16
+ description: "Iconify icon name to override the default theme icon",
17
+ table: { category: "Appearance" },
18
+ },
19
+ dismissible: {
20
+ control: "boolean",
21
+ description: "Show a close button (emits 'dismiss' on click)",
22
+ table: { category: "Behaviour" },
23
+ },
24
+ maskConfig: { table: { disable: true } },
25
+ contentId: { table: { disable: true } },
26
+ ariaLive: { table: { disable: true } },
27
+ },
28
+ args: {
29
+ theme: "info",
30
+ dismissible: false,
31
+ },
32
+ };
33
+
34
+ export default meta;
35
+ type Story = StoryObj<typeof AlertMaskedContent>;
36
+
37
+ const wrapperStyle = `
38
+ max-width: 600px;
39
+ padding: 2rem;
40
+ background: linear-gradient(135deg, oklch(40% 0.15 250), oklch(25% 0.1 300));
41
+ border-radius: 8px;
42
+ `;
43
+
44
+ /** Default — info theme over a coloured background to show the glass effect. */
45
+ export const Default: Story = {
46
+ render: (args) => ({
47
+ components: { AlertMaskedContent },
48
+ setup() {
49
+ return { args };
50
+ },
51
+ template: `
52
+ <div :data-theme="args.theme" :style="'${wrapperStyle}'">
53
+ <AlertMaskedContent v-bind="args">
54
+ <template #title>Alert title</template>
55
+ <template #content>This is the alert body. It describes what happened and what the user should do next.</template>
56
+ </AlertMaskedContent>
57
+ </div>
58
+ `,
59
+ }),
60
+ };
61
+
62
+ /** Dismissible — renders the close button. */
63
+ export const Dismissible: Story = {
64
+ args: { theme: "info", dismissible: true },
65
+ render: (args) => ({
66
+ components: { AlertMaskedContent },
67
+ setup() {
68
+ return { args };
69
+ },
70
+ template: `
71
+ <div :data-theme="args.theme" :style="'${wrapperStyle}'">
72
+ <AlertMaskedContent v-bind="args">
73
+ <template #title>Dismissible alert</template>
74
+ <template #content>Click the close button to emit the dismiss event.</template>
75
+ </AlertMaskedContent>
76
+ </div>
77
+ `,
78
+ }),
79
+ };
80
+
81
+ /** All themes — all four semantic variants stacked over a shared background. */
82
+ export const AllThemes: Story = {
83
+ name: "All Themes",
84
+ render: () => ({
85
+ components: { AlertMaskedContent },
86
+ setup() {
87
+ return { themes: ["info", "success", "warning", "error"] as const };
88
+ },
89
+ template: `
90
+ <div style="${wrapperStyle} display: flex; flex-direction: column; gap: 1.2rem;">
91
+ <div v-for="theme in themes" :key="theme" :data-theme="theme">
92
+ <AlertMaskedContent :theme="theme" :dismissible="true">
93
+ <template #title>{{ theme.charAt(0).toUpperCase() + theme.slice(1) }}</template>
94
+ <template #content>This is the {{ theme }} masked variant.</template>
95
+ </AlertMaskedContent>
96
+ </div>
97
+ </div>
98
+ `,
99
+ }),
100
+ };
101
+
102
+ /** Compared side-by-side with different background colours to show how the glass adapts. */
103
+ export const BackgroundVariants: Story = {
104
+ name: "Background Variants",
105
+ render: () => ({
106
+ components: { AlertMaskedContent },
107
+ setup() {
108
+ return {
109
+ backgrounds: [
110
+ "linear-gradient(135deg, oklch(40% 0.15 250), oklch(25% 0.1 300))",
111
+ "linear-gradient(135deg, oklch(35% 0.12 30), oklch(20% 0.08 60))",
112
+ "linear-gradient(135deg, oklch(20% 0 0), oklch(10% 0 0))",
113
+ ],
114
+ };
115
+ },
116
+ template: `
117
+ <div style="display: flex; flex-direction: column; gap: 1.6rem;">
118
+ <div
119
+ v-for="(bg, i) in backgrounds"
120
+ :key="i"
121
+ :style="{ background: bg, padding: '2rem', borderRadius: '8px', maxWidth: '500px' }"
122
+ data-theme="info"
123
+ >
124
+ <AlertMaskedContent theme="info" :dismissible="true">
125
+ <template #title>Glass effect</template>
126
+ <template #content>The masked border adapts to whatever sits behind it.</template>
127
+ </AlertMaskedContent>
128
+ </div>
129
+ </div>
130
+ `,
131
+ }),
132
+ };
@@ -0,0 +1,149 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { mountSuspended } from "@nuxt/test-utils/runtime";
3
+ import AlertMaskedContent from "../AlertMaskedContent.vue";
4
+
5
+ const mockResizeObserver = vi.fn(() => ({
6
+ observe: vi.fn(),
7
+ unobserve: vi.fn(),
8
+ disconnect: vi.fn(),
9
+ }));
10
+
11
+ vi.stubGlobal("ResizeObserver", mockResizeObserver);
12
+
13
+ describe("AlertMaskedContent", () => {
14
+ beforeEach(() => {
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ // ─── Mount ────────────────────────────────────────────────────────────────
19
+
20
+ it("mounts without error", async () => {
21
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
22
+ expect(wrapper.vm).toBeTruthy();
23
+ });
24
+
25
+ // ─── Root element ─────────────────────────────────────────────────────────
26
+
27
+ it("renders the root element with class alert-masked-content", async () => {
28
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
29
+ expect(wrapper.find(".alert-masked-content").exists()).toBe(true);
30
+ });
31
+
32
+ it("sets data-theme on the root element", async () => {
33
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "success" } });
34
+ expect(wrapper.find(".alert-masked-content").attributes("data-theme")).toBe("success");
35
+ });
36
+
37
+ // ─── AlertMaskCore ────────────────────────────────────────────────────────
38
+
39
+ it("renders AlertMaskCore", async () => {
40
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
41
+ expect(wrapper.find(".alert-mask-core").exists()).toBe(true);
42
+ });
43
+
44
+ it("renders AlertContentInner inside AlertMaskCore", async () => {
45
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
46
+ expect(wrapper.find(".alert-mask-core .alert-content-inner").exists()).toBe(true);
47
+ });
48
+
49
+ // ─── Icon ─────────────────────────────────────────────────────────────────
50
+
51
+ it("renders the icon region", async () => {
52
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
53
+ expect(wrapper.find("[data-test-id='alert-icon']").exists()).toBe(true);
54
+ });
55
+
56
+ it("replaces the icon via the #icon slot", async () => {
57
+ const wrapper = await mountSuspended(AlertMaskedContent, {
58
+ props: { theme: "info" },
59
+ slots: { icon: '<span class="custom-icon">★</span>' },
60
+ });
61
+ expect(wrapper.find(".custom-icon").exists()).toBe(true);
62
+ });
63
+
64
+ // ─── Title slot ───────────────────────────────────────────────────────────
65
+
66
+ it("renders the title element when the #title slot is provided", async () => {
67
+ const wrapper = await mountSuspended(AlertMaskedContent, {
68
+ props: { theme: "info" },
69
+ slots: { title: "Important notice" },
70
+ });
71
+ expect(wrapper.find("[data-test-id='alert-title']").text()).toContain("Important notice");
72
+ });
73
+
74
+ it("does not render the title element when the #title slot is not provided", async () => {
75
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
76
+ expect(wrapper.find("[data-test-id='alert-title']").exists()).toBe(false);
77
+ });
78
+
79
+ // ─── Content slot ─────────────────────────────────────────────────────────
80
+
81
+ it("renders the content element when the #content slot is provided", async () => {
82
+ const wrapper = await mountSuspended(AlertMaskedContent, {
83
+ props: { theme: "info" },
84
+ slots: { content: "More detail here." },
85
+ });
86
+ expect(wrapper.find("[data-test-id='alert-content']").text()).toContain("More detail here.");
87
+ });
88
+
89
+ it("does not render the content element when the #content slot is not provided", async () => {
90
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
91
+ expect(wrapper.find("[data-test-id='alert-content']").exists()).toBe(false);
92
+ });
93
+
94
+ // ─── contentId / ariaLive ─────────────────────────────────────────────────
95
+
96
+ it("sets id on the body element when contentId is provided", async () => {
97
+ const wrapper = await mountSuspended(AlertMaskedContent, {
98
+ props: { theme: "info", contentId: "toast-message-xyz" },
99
+ });
100
+ expect(wrapper.find(".alert-content-body").attributes("id")).toBe("toast-message-xyz");
101
+ });
102
+
103
+ it("sets aria-live on the body element when ariaLive is provided", async () => {
104
+ const wrapper = await mountSuspended(AlertMaskedContent, {
105
+ props: { theme: "info", ariaLive: "assertive" },
106
+ });
107
+ expect(wrapper.find(".alert-content-body").attributes("aria-live")).toBe("assertive");
108
+ });
109
+
110
+ // ─── Dismiss button ───────────────────────────────────────────────────────
111
+
112
+ it("does not render the dismiss button when dismissible is false", async () => {
113
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info", dismissible: false } });
114
+ expect(wrapper.find("[data-test-id='alert-dismiss']").exists()).toBe(false);
115
+ });
116
+
117
+ it("renders the dismiss button when dismissible is true", async () => {
118
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info", dismissible: true } });
119
+ expect(wrapper.find("[data-test-id='alert-dismiss']").exists()).toBe(true);
120
+ });
121
+
122
+ it("emits the dismiss event when the dismiss button is clicked", async () => {
123
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info", dismissible: true } });
124
+ await wrapper.find("[data-test-id='alert-dismiss']").trigger("click");
125
+ expect(wrapper.emitted("dismiss")).toBeTruthy();
126
+ });
127
+
128
+ // ─── Default maskConfig ───────────────────────────────────────────────────
129
+
130
+ it("passes the resolved maskConfig to AlertMaskCore", async () => {
131
+ const wrapper = await mountSuspended(AlertMaskedContent, { props: { theme: "info" } });
132
+ const contentEl = wrapper.find(".alert-mask-content");
133
+ const style = (contentEl.element as HTMLElement).style;
134
+ // Default borderLeft: 6 → --insetInlineStart: 6px
135
+ expect(style.getPropertyValue("--insetInlineStart")).toBe("6px");
136
+ expect(style.getPropertyValue("--insetBlockStart")).toBe("1px");
137
+ expect(style.getPropertyValue("--insetInlineEnd")).toBe("1px");
138
+ expect(style.getPropertyValue("--insetBlockEnd")).toBe("1px");
139
+ });
140
+
141
+ it("merges custom maskConfig over defaults", async () => {
142
+ const wrapper = await mountSuspended(AlertMaskedContent, {
143
+ props: { theme: "info", maskConfig: { borderLeft: 12 } },
144
+ });
145
+ const contentEl = wrapper.find(".alert-mask-content");
146
+ const style = (contentEl.element as HTMLElement).style;
147
+ expect(style.getPropertyValue("--insetInlineStart")).toBe("12px");
148
+ });
149
+ });
@@ -10,7 +10,7 @@
10
10
  class="input-button-core"
11
11
  :class="buttonClasses"
12
12
  >
13
- <PendingEffect v-if="hasPendingEffect" />
13
+ <PendingEffect v-if="hasPendingEffect" :theme="theme" />
14
14
 
15
15
  <span v-if="hasLeftSlot" class="btn-icon left">
16
16
  <slot name="left"></slot>
@@ -87,7 +87,7 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
87
87
  <style lang="css">
88
88
  @layer components {
89
89
  .input-button-core {
90
- all: unset;
90
+ /* all: unset; */
91
91
 
92
92
  display: grid;
93
93
  grid-auto-flow: column;
@@ -108,53 +108,52 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
108
108
  }
109
109
 
110
110
  /*
111
- * Variants
112
- **/
113
- &.primary {
114
- background-color: var(--theme-button-primary-surface);
115
- color: var(--theme-button-primary-text);
116
- border: var(--button-border-width) solid var(--theme-button-primary-border);
117
- outline: var(--button-outline-width) solid var(--theme-button-primary-outline);
118
-
119
- &:hover,
120
- &:focus-visible {
121
- background-color: var(--theme-button-secondary-surface);
122
- color: var(--theme-button-secondary-text);
123
- border-color: var(--theme-button-primary-border-active);
124
- outline-color: var(--theme-button-primary-outline-active);
125
- }
111
+ * Theming
112
+ **/
113
+ background-color: var(--theme-surface);
114
+ color: var(--theme-on-surface);
115
+ border: var(--button-border-width) solid var(--theme-border);
116
+ outline: var(--button-outline-width) solid var(--theme-ring);
117
+
118
+ &:hover,
119
+ &:focus-visible {
120
+ background-color: var(--theme-surface-hover);
121
+ color: var(--theme-text);
122
+ border-color: var(--theme-border-focus);
123
+ outline-color: var(--theme-ring);
124
+ }
126
125
 
127
- &.is-pending {
128
- background-color: color-mix(in oklab, var(--theme-button-primary-surface) 50%, transparent);
129
- }
126
+ &.is-pending {
127
+ background-color: color-mix(in oklab, var(--theme-surface) 50%, transparent);
130
128
  }
131
129
 
132
130
  &.secondary {
133
- background-color: var(--theme-button-secondary-surface);
134
- border: var(--button-border-width) solid var(--theme-button-secondary-border);
135
- color: var(--theme-button-secondary-text);
136
- outline: var(--button-outline-width) solid var(--theme-button-secondary-outline);
131
+ background-color: var(--theme-surface-inverted);
132
+ border: var(--button-border-width) solid var(--theme-border);
133
+ color: var(--theme-text-inverted);
134
+ outline: var(--button-outline-width) solid var(--theme-ring);
137
135
 
138
136
  &:hover,
139
137
  &:focus-visible {
140
- background-color: var(--theme-button-primary-surface);
141
- color: var(--theme-button-primary-text);
142
- border-color: var(--theme-button-secondary-border-active);
143
- outline-color: var(--theme-button-secondary-outline-active);
138
+ background-color: var(--theme-surface);
139
+ color: var(--theme-on-surface);
140
+ border-color: var(--theme-border-focus);
141
+ outline-color: var(--theme-surface);
144
142
  }
145
143
  }
146
144
 
147
145
  &.tertiary {
148
- background-color: var(--theme-button-tertiary-surface);
149
- border: var(--button-border-width) solid transparent;
150
- color: var(--theme-button-tertiary-text);
146
+ background-color: light-dark(var(--slate-01), transparent);
147
+ border: var(--button-border-width) solid var(--theme-border);
148
+ color: var(--theme-text);
151
149
  text-decoration: underline;
152
- outline: var(--button-outline-width) solid transparent;
150
+ outline: var(--button-outline-width) solid var(--theme-border-focus);
153
151
 
154
152
  &:hover,
155
153
  &:focus-visible {
156
- border-color: var(--theme-button-tertiary-border-active);
157
- outline-color: var(--theme-button-tertiary-outline-active);
154
+ background-color: var(--theme-surface-hover);
155
+ border-color: var(--theme-border-focus);
156
+ outline-color: var(--theme-border-focus);
158
157
  }
159
158
  }
160
159
 
@@ -180,11 +179,8 @@ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
180
179
 
181
180
  &[readonly] {
182
181
  opacity: 0.5;
183
- &:hover,
184
- &:focus-visible {
185
- cursor: not-allowed;
186
- pointer-events: none;
187
- }
182
+ cursor: not-allowed;
183
+ pointer-events: none;
188
184
  }
189
185
 
190
186
  .button-text {
@@ -100,22 +100,22 @@ const flexDirection = ref(props.direction);
100
100
  --_white-space: nowrap;
101
101
  }
102
102
  background-color: var(--theme-input-surface);
103
- border: var(--form-element-border-width) solid var(--theme-input-border);
104
- outline: var(--form-element-outline-width) solid var(--theme-input-outline);
103
+ border: var(--form-element-border-width) solid var(--theme-border);
104
+ outline: var(--form-element-outline-width) solid transparent;
105
105
 
106
106
  box-shadow: 0.1rem 0.1rem 0.8rem 0.1rem transparent;
107
107
 
108
108
  &:hover {
109
109
  background-color: var(--theme-input-surface-hover);
110
- border-color: var(--theme-input-border);
111
- outline-color: var(--theme-input-outline-hover);
110
+ border-color: var(--theme-border);
111
+ outline-color: var(--theme-ring);
112
112
  outline-offset: var(--form-element-outline-offset-focus);
113
113
  cursor: pointer;
114
114
  }
115
115
 
116
116
  &:has(.input-checkbox-radio-core:focus-visible) {
117
- background-color: var(--theme-input-surface-focus);
118
- outline-color: var(--theme-input-outline-focus);
117
+ background-color: var(--theme-surface-subtle);
118
+ outline-color: var(--theme-border-focus);
119
119
  outline-offset: var(--form-element-outline-offset-focus);
120
120
  }
121
121
 
@@ -126,7 +126,7 @@ const flexDirection = ref(props.direction);
126
126
  .input-checkbox-radio-options-button-label {
127
127
  display: flex;
128
128
  flex-grow: 1;
129
- color: var(--theme-checkbox-label-text-color);
129
+ color: var(--colour-text-default);
130
130
  font-size: var(--input-font-size);
131
131
  width: 100%;
132
132
  min-height: var(--input-element-line-height);
@@ -145,7 +145,7 @@ const flexDirection = ref(props.direction);
145
145
  display: flex;
146
146
  align-items: center;
147
147
  justify-content: center;
148
- color: var(--theme-checkbox-decorator-color);
148
+ color: var(--theme-text);
149
149
 
150
150
  .icon {
151
151
  height: var(--input-checkbox-decorator-icon-size);
@@ -113,8 +113,8 @@ const inputClasses = computed(() => [
113
113
  place-content: center;
114
114
 
115
115
  background-color: var(--theme-checkbox-symbol-surface);
116
- border: 0.1rem solid var(--theme-input-border);
117
- outline: var(--form-element-outline-width) solid var(--theme-input-outline);
116
+ border: 0.1rem solid var(--theme-border);
117
+ outline: var(--form-element-outline-width) solid transparent;
118
118
 
119
119
  height: var(--input-checked-element-size);
120
120
  width: var(--input-checked-element-size);
@@ -139,7 +139,7 @@ const inputClasses = computed(() => [
139
139
 
140
140
  &:not(:is(.button)) {
141
141
  &:has(input:focus-visible) {
142
- outline: var(--form-element-outline-width-focus) solid var(--theme-input-outline-focus);
142
+ outline: var(--form-element-outline-width-focus) solid var(--theme-border-focus);
143
143
  outline-offset: var(--form-element-outline-offset-focus);
144
144
  }
145
145
  }
@@ -150,7 +150,7 @@ const inputClasses = computed(() => [
150
150
 
151
151
  .input-checked-icon-checked,
152
152
  .icon {
153
- color: var(--theme-checkbox-symbol-color);
153
+ color: var(--theme-text);
154
154
  }
155
155
  }
156
156
  }
@@ -164,7 +164,7 @@ const inputClasses = computed(() => [
164
164
 
165
165
  .input-checked-icon-checked,
166
166
  .icon {
167
- color: var(--theme-checkbox-symbol-color);
167
+ color: var(--theme-text);
168
168
  height: var(--input-checked-icon-size);
169
169
  width: var(--input-checked-icon-size);
170
170
  box-shadow: var(--_box-shadow);
@@ -79,7 +79,7 @@ watch(
79
79
  display: flex;
80
80
  align-items: stretch;
81
81
  overflow: hidden;
82
- border: var(--form-element-border-width) solid var(--theme-input-border);
82
+ border: var(--form-element-border-width) solid var(--theme-border);
83
83
  border-radius: var(--form-input-border-radius);
84
84
  background-color: var(--theme-input-surface);
85
85
  transition: all var(--theme-form-transition-duration) ease-in-out;
@@ -101,19 +101,19 @@ watch(
101
101
 
102
102
  .input-copy-button.input-button-core {
103
103
  border-radius: 0;
104
- border-inline-start: var(--form-element-border-width) solid var(--theme-input-border);
104
+ border-inline-start: var(--form-element-border-width) solid var(--theme-border);
105
105
  padding-inline: var(--input-padding-inline);
106
106
  min-width: var(--input-min-height);
107
- background-color: var(--theme-button-secondary-surface);
108
- color: var(--theme-button-secondary-text);
107
+ background-color: transparent;
108
+ color: var(--theme-text);
109
109
 
110
110
  &:hover {
111
- background-color: var(--theme-button-primary-surface);
112
- color: var(--theme-button-primary-text);
111
+ background-color: var(--theme-surface);
112
+ color: var(--theme-on-surface);
113
113
  }
114
114
 
115
115
  &:focus-visible {
116
- outline: var(--form-element-outline-width-focus) solid var(--theme-input-outline-focus);
116
+ outline: var(--form-element-outline-width-focus) solid var(--theme-border-focus);
117
117
  outline-offset: -4px;
118
118
  }
119
119
  }
@@ -71,10 +71,10 @@ const minLength = computed(() => `${props.max.toString().length + 1}em`);
71
71
 
72
72
  width: fit-content;
73
73
 
74
- background-color: var(--theme-button-surface);
74
+ background-color: var(--theme-input-surface);
75
75
  border-radius: var(--form-element-border-width);
76
- border: var(--form-element-border-width) solid var(--theme-input-border);
77
- outline: var(--form-element-outline-width) solid var(--theme-input-outline);
76
+ border: var(--form-element-border-width) solid var(--theme-border);
77
+ outline: var(--form-element-outline-width) solid transparent;
78
78
  box-shadow: var(--_focus-box-shadow);
79
79
 
80
80
  .slot {
@@ -144,12 +144,12 @@ const minLength = computed(() => `${props.max.toString().length + 1}em`);
144
144
 
145
145
  .left-slot {
146
146
  margin-inline-end: 0;
147
- border-right: 2px solid var(--theme-button-surface-hover);
147
+ border-right: 2px solid var(--theme-input-surface-hover);
148
148
  }
149
149
 
150
150
  .right-slot {
151
151
  margin-inline-end: 0;
152
- border-left: 2px solid var(--theme-button-surface-hover);
152
+ border-left: 2px solid var(--theme-input-surface-hover);
153
153
  }
154
154
  }
155
155
  }
@@ -81,18 +81,18 @@ const fieldData = defineModel("fieldData") as Ref<IFormMultipleOptions>;
81
81
  transition: all var(--theme-form-transition-duration) ease-in-out;
82
82
 
83
83
  &.normal {
84
- border: var(--form-element-border-width) solid var(--theme-input-border);
84
+ border: var(--form-element-border-width) solid var(--theme-border);
85
85
  border-radius: var(--form-input-border-radius);
86
- outline: var(--form-element-outline-width) solid var(--theme-input-outline);
86
+ outline: var(--form-element-outline-width) solid transparent;
87
87
  }
88
88
 
89
89
  &.underlined {
90
- border-bottom: var(--form-element-border-bottom-width-underlined) solid var(--theme-input-border);
90
+ border-bottom: var(--form-element-border-bottom-width-underlined) solid var(--theme-border);
91
91
  background-color: var(--theme-input-surface);
92
92
  }
93
93
 
94
94
  &:has(select:focus-visible, :hover) {
95
- outline: var(--form-element-outline-width-focus) solid var(--theme-input-outline-focus);
95
+ outline: var(--form-element-outline-width-focus) solid var(--theme-border-focus);
96
96
  outline-offset: var(--form-element-outline-offset-focus);
97
97
  }
98
98
 
@@ -105,7 +105,7 @@ const fieldData = defineModel("fieldData") as Ref<IFormMultipleOptions>;
105
105
  content: '';
106
106
  width: 0.8em;
107
107
  height: 0.5em;
108
- background-color: var(--theme-input-border);
108
+ background-color: var(--theme-border);
109
109
  clip-path: polygon(100% 0%, 0 0%, 50% 100%);
110
110
  } */
111
111
 
@@ -128,7 +128,7 @@ const fieldData = defineModel("fieldData") as Ref<IFormMultipleOptions>;
128
128
 
129
129
  &:open::picker(select) {
130
130
  opacity: 1;
131
- border: var(--form-element-border-width) solid var(--theme-input-border);
131
+ border: var(--form-element-border-width) solid var(--theme-border);
132
132
  outline: var(--form-element-outline-width) solid var(--_input-select-outline-color);
133
133
 
134
134
  @starting-style {
@@ -138,25 +138,25 @@ onMounted(() => {
138
138
  position: relative;
139
139
 
140
140
  &.normal {
141
- border: var(--form-element-border-width) solid var(--theme-input-border);
141
+ border: var(--form-element-border-width) solid var(--theme-border);
142
142
  border-radius: var(--form-input-border-radius);
143
- outline: var(--form-element-outline-width) solid var(--theme-input-outline);
143
+ outline: var(--form-element-outline-width) solid transparent;
144
144
 
145
145
  padding-inline: var(--input-padding-inline);
146
146
 
147
147
  &:has(input:is(:hover), button:is(:hover)) {
148
- outline: var(--form-element-outline-width-focus) solid var(--theme-input-outline-focus);
148
+ outline: var(--form-element-outline-width-focus) solid var(--theme-border-focus);
149
149
  outline-offset: var(--form-element-outline-offset-focus);
150
150
  }
151
151
 
152
152
  &:has(input:focus-visible, button:focus-visible) {
153
- outline: var(--form-element-outline-width-focus) solid var(--theme-input-outline-focus);
153
+ outline: var(--form-element-outline-width-focus) solid var(--theme-border-focus);
154
154
  outline-offset: var(--form-element-outline-offset-focus);
155
155
  }
156
156
  }
157
157
 
158
158
  &.underlined {
159
- border-bottom: var(--form-element-border-bottom-width-underlined) solid var(--theme-input-border);
159
+ border-bottom: var(--form-element-border-bottom-width-underlined) solid var(--theme-border);
160
160
  padding-inline: var(--input-padding-inline);
161
161
  }
162
162
 
@@ -181,7 +181,7 @@ onMounted(() => {
181
181
  }
182
182
 
183
183
  &:is(:focus-visible) {
184
- outline: var(--form-element-outline-width-focus) solid var(--theme-input-outline-focus);
184
+ outline: var(--form-element-outline-width-focus) solid var(--theme-border-focus);
185
185
  outline-offset: -4px;
186
186
  }
187
187
 
@@ -180,13 +180,13 @@ updateElementClasses(["input-text-as-number", "has-left-button", "has-right-butt
180
180
 
181
181
  &.left-slot {
182
182
  .input-button-core {
183
- border-right: var(--form-element-border-width) solid var(--theme-input-border);
183
+ border-right: var(--form-element-border-width) solid var(--theme-border);
184
184
  }
185
185
  }
186
186
 
187
187
  &.right-slot {
188
188
  .input-button-core {
189
- border-left: var(--form-element-border-width) solid var(--theme-input-border);
189
+ border-left: var(--form-element-border-width) solid var(--theme-border);
190
190
  }
191
191
  }
192
192
  }