@300codes/design-system 1.0.0

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 (47) hide show
  1. package/README.md +155 -0
  2. package/package.json +63 -0
  3. package/src/components/BaseIcon/BaseIcon.stories.ts +66 -0
  4. package/src/components/BaseIcon/BaseIcon.vue +96 -0
  5. package/src/components/BaseIcon/index.ts +2 -0
  6. package/src/components/BaseLabel/BaseLabel.stories.ts +114 -0
  7. package/src/components/BaseLabel/BaseLabel.vue +149 -0
  8. package/src/components/BaseLabel/index.ts +2 -0
  9. package/src/components/BaseTooltip/BaseTooltip.stories.ts +113 -0
  10. package/src/components/BaseTooltip/BaseTooltip.vue +123 -0
  11. package/src/components/BaseTooltip/index.ts +2 -0
  12. package/src/components/ButtonWithIcon/ButtonWithIcon.stories.ts +149 -0
  13. package/src/components/ButtonWithIcon/ButtonWithIcon.vue +77 -0
  14. package/src/components/ButtonWithIcon/index.ts +2 -0
  15. package/src/components/CheckboxInput/CheckboxInput.stories.ts +99 -0
  16. package/src/components/CheckboxInput/CheckboxInput.vue +176 -0
  17. package/src/components/CheckboxInput/index.ts +2 -0
  18. package/src/components/LabelInput/LabelInput.vue +111 -0
  19. package/src/components/LabelInput/index.ts +2 -0
  20. package/src/components/RadioInput/RadioInput.stories.ts +114 -0
  21. package/src/components/RadioInput/RadioInput.vue +174 -0
  22. package/src/components/RadioInput/index.ts +2 -0
  23. package/src/components/SearchInput/SearchInput.stories.ts +103 -0
  24. package/src/components/SearchInput/SearchInput.vue +83 -0
  25. package/src/components/SearchInput/index.ts +2 -0
  26. package/src/components/SelectInput/SelectInput.stories.ts +111 -0
  27. package/src/components/SelectInput/SelectInput.vue +497 -0
  28. package/src/components/SelectInput/index.ts +2 -0
  29. package/src/components/SelectInputField/SelectInputField.stories.ts +141 -0
  30. package/src/components/SelectInputField/SelectInputField.vue +64 -0
  31. package/src/components/SelectInputField/index.ts +2 -0
  32. package/src/components/SimpleButton/SimpleButton.stories.ts +143 -0
  33. package/src/components/SimpleButton/SimpleButton.vue +193 -0
  34. package/src/components/SimpleButton/index.ts +2 -0
  35. package/src/components/TabsList/TabsList.stories.ts +83 -0
  36. package/src/components/TabsList/TabsList.vue +156 -0
  37. package/src/components/TabsList/index.ts +2 -0
  38. package/src/components/TextInput/TextInput.stories.ts +125 -0
  39. package/src/components/TextInput/TextInput.vue +273 -0
  40. package/src/components/TextInput/components/InputIconButton.vue +54 -0
  41. package/src/components/TextInput/index.ts +2 -0
  42. package/src/components/TextInputField/TextInputField.stories.ts +133 -0
  43. package/src/components/TextInputField/TextInputField.vue +93 -0
  44. package/src/components/TextInputField/index.ts +2 -0
  45. package/src/components/index.ts +15 -0
  46. package/src/css/tokens.css +417 -0
  47. package/src/types/icon.ts +1 -0
@@ -0,0 +1,133 @@
1
+ import { ref } from 'vue';
2
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
3
+ import type { ConcreteComponent } from 'vue';
4
+ import type { TextInputFieldProps } from './TextInputField.vue';
5
+ import TextInputField from './TextInputField.vue';
6
+
7
+ const meta: Meta<TextInputFieldProps> = {
8
+ title: 'Form/TextInputField',
9
+ component: TextInputField as unknown as ConcreteComponent<TextInputFieldProps>,
10
+ tags: ['autodocs'],
11
+ decorators: [
12
+ () => ({ template: '<div style="max-width: 25rem; width: 100%;"><story /></div>' }),
13
+ ],
14
+ argTypes: {
15
+ size: { control: 'select', options: ['sm', 'md', 'lg'] },
16
+ type: { control: 'select', options: ['text', 'password', 'email', 'tel', 'search'] },
17
+ filter: { control: 'select', options: [undefined, 'number', 'number-dash', 'alpha', 'alpha-space'] },
18
+ inputmode: { control: 'select', options: [undefined, 'numeric'] },
19
+ invalid: { control: 'boolean' },
20
+ required: { control: 'boolean' },
21
+ disabled: { control: 'boolean' },
22
+ },
23
+ };
24
+
25
+ export default meta;
26
+ type Story = StoryObj<TextInputFieldProps>;
27
+
28
+ export const Default: Story = {
29
+ args: { name: 'default', label: 'Email address', placeholder: 'Enter value', size: 'md' },
30
+ render: (args: TextInputFieldProps) => ({
31
+ components: { TextInputField },
32
+ setup() {
33
+ const value = ref('');
34
+ return { args, value };
35
+ },
36
+ template: '<TextInputField v-bind="args" v-model="value" />',
37
+ }),
38
+ };
39
+
40
+ export const WithMessage: Story = {
41
+ args: {
42
+ name: 'with-message',
43
+ label: 'Email',
44
+ message: 'Invalid email address',
45
+ invalid: true,
46
+ size: 'md',
47
+ },
48
+ render: (args: TextInputFieldProps) => ({
49
+ components: { TextInputField },
50
+ setup() {
51
+ const value = ref('wrong@');
52
+ return { args, value };
53
+ },
54
+ template: '<TextInputField v-bind="args" v-model="value" />',
55
+ }),
56
+ };
57
+
58
+ export const Valid: Story = {
59
+ args: {
60
+ name: 'valid',
61
+ label: 'Email',
62
+ message: '',
63
+ invalid: false,
64
+ size: 'md',
65
+ },
66
+ render: (args: TextInputFieldProps) => ({
67
+ components: { TextInputField },
68
+ setup() {
69
+ const value = ref('user@example.com');
70
+ return { args, value };
71
+ },
72
+ template: '<TextInputField v-bind="args" v-model="value" />',
73
+ }),
74
+ };
75
+
76
+ export const Required: Story = {
77
+ args: { name: 'required', label: 'Full name', required: true, size: 'md' },
78
+ render: (args: TextInputFieldProps) => ({
79
+ components: { TextInputField },
80
+ setup() {
81
+ const value = ref('');
82
+ return { args, value };
83
+ },
84
+ template: '<TextInputField v-bind="args" v-model="value" />',
85
+ }),
86
+ };
87
+
88
+ export const WithIconLeft: Story = {
89
+ args: {
90
+ name: 'icon-left',
91
+ label: 'Search',
92
+ iconLeft: { name: 'search', ariaLabel: 'Search' },
93
+ },
94
+ render: (args: TextInputFieldProps) => ({
95
+ components: { TextInputField },
96
+ setup() {
97
+ const value = ref('');
98
+ return { args, value };
99
+ },
100
+ template: '<TextInputField v-bind="args" v-model="value" />',
101
+ }),
102
+ };
103
+
104
+ export const Disabled: Story = {
105
+ args: { name: 'disabled', label: 'Username', disabled: true },
106
+ render: (args: TextInputFieldProps) => ({
107
+ components: { TextInputField },
108
+ setup() {
109
+ const value = ref('Disabled value');
110
+ return { args, value };
111
+ },
112
+ template: '<TextInputField v-bind="args" v-model="value" />',
113
+ }),
114
+ };
115
+
116
+ export const Sizes: Story = {
117
+ render: () => ({
118
+ components: { TextInputField },
119
+ setup() {
120
+ const sm = ref('');
121
+ const md = ref('');
122
+ const lg = ref('');
123
+ return { sm, md, lg };
124
+ },
125
+ template: `
126
+ <div class="flex flex-col gap-4 w-80">
127
+ <TextInputField name="sm" label="Small" size="sm" v-model="sm" />
128
+ <TextInputField name="md" label="Medium" size="md" v-model="md" />
129
+ <TextInputField name="lg" label="Large" size="lg" v-model="lg" />
130
+ </div>
131
+ `,
132
+ }),
133
+ };
@@ -0,0 +1,93 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from 'vue';
3
+ import TextInput from '../TextInput/TextInput.vue';
4
+ import LabelInput from '../LabelInput/LabelInput.vue';
5
+ import type { TextInputIcon, InputType, FilterType } from '../TextInput/TextInput.vue';
6
+
7
+ export interface TextInputFieldProps {
8
+ name: string;
9
+ label: string;
10
+ id?: string;
11
+ type?: InputType;
12
+ iconLeft?: TextInputIcon;
13
+ iconRight?: TextInputIcon;
14
+ placeholder?: string;
15
+ autocomplete?: string;
16
+ invalid?: boolean | null;
17
+ message?: string;
18
+ required?: boolean;
19
+ disabled?: boolean;
20
+ size?: 'sm' | 'md' | 'lg';
21
+ filter?: FilterType;
22
+ inputmode?: 'numeric';
23
+ }
24
+
25
+ const props = withDefaults(defineProps<TextInputFieldProps>(), {
26
+ type: 'text',
27
+ placeholder: '',
28
+ size: 'md',
29
+ invalid: null,
30
+ message: '',
31
+ id: undefined,
32
+ iconLeft: undefined,
33
+ iconRight: undefined,
34
+ autocomplete: undefined,
35
+ filter: undefined,
36
+ inputmode: undefined,
37
+ });
38
+
39
+ const emit = defineEmits<{
40
+ focus: [FocusEvent];
41
+ blur: [FocusEvent];
42
+ clickIcon: ['left' | 'right'];
43
+ enter: [];
44
+ }>();
45
+
46
+ const model = defineModel<string>({ required: true });
47
+
48
+ const textInputRef = ref<InstanceType<typeof TextInput>>();
49
+
50
+ const textInputInvalid = computed(() =>
51
+ typeof props.invalid === 'boolean' ? props.invalid : undefined
52
+ );
53
+
54
+ function focus() {
55
+ textInputRef.value?.el?.focus();
56
+ }
57
+
58
+ defineExpose({ focus });
59
+ </script>
60
+
61
+ <template>
62
+ <LabelInput
63
+ :name="id || name"
64
+ :label="label"
65
+ :message="message"
66
+ :required="required"
67
+ :invalid="invalid"
68
+ :disabled="disabled"
69
+ :size="size"
70
+ >
71
+ <TextInput
72
+ :id="id"
73
+ ref="textInputRef"
74
+ v-model="model"
75
+ :name="name"
76
+ :type="type"
77
+ :icon-left="iconLeft"
78
+ :icon-right="iconRight"
79
+ :placeholder="placeholder"
80
+ :autocomplete="autocomplete"
81
+ :invalid="textInputInvalid"
82
+ :required="required"
83
+ :disabled="disabled"
84
+ :size="size"
85
+ :filter="filter"
86
+ :inputmode="inputmode"
87
+ @focus="emit('focus', $event)"
88
+ @blur="emit('blur', $event)"
89
+ @click-icon="emit('clickIcon', $event)"
90
+ @enter="emit('enter')"
91
+ />
92
+ </LabelInput>
93
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as TextInputField } from './TextInputField.vue';
2
+ export type { TextInputFieldProps } from './TextInputField.vue';
@@ -0,0 +1,15 @@
1
+ export * from './BaseLabel/index';
2
+ export * from './SimpleButton/index';
3
+ export * from './BaseIcon/index';
4
+ export * from './ButtonWithIcon/index';
5
+ export * from './LabelInput/index';
6
+ export * from './TextInput/index';
7
+ export * from './TextInputField/index';
8
+ export * from './SelectInput/index';
9
+ export * from './SelectInputField/index';
10
+ export * from './CheckboxInput/index';
11
+ export * from './RadioInput/index';
12
+ export * from './TabsList/index';
13
+ export * from './SearchInput/index';
14
+ export * from './BaseTooltip/index';
15
+ export type { IconSize } from '../types/icon';
@@ -0,0 +1,417 @@
1
+ /*
2
+ * 300codes Design System — Tokens
3
+ * =================================
4
+ * Copy this file to your project and customize the values.
5
+ * Components work without this file — they have built-in fallback values.
6
+ * Importing this file maps your Tailwind theme colors to component tokens.
7
+ *
8
+ * Requires Tailwind CSS — theme() resolves values from your @theme config.
9
+ *
10
+ * CSS is compiled at the consumer's build time. Add an @source directive
11
+ * to your project's main CSS file so Tailwind scans design system components:
12
+ *
13
+ * @source "../../node_modules/@300codes/design-system/src/**\/*.{vue,ts}";
14
+ *
15
+ * Usage in Astro (src/css/base.css):
16
+ *
17
+ * @import "tailwindcss";
18
+ * @source "../../node_modules/@300codes/design-system/src/**\/*.{vue,ts}";
19
+ * @import "./tokens.css";
20
+ *
21
+ * Usage in Nuxt (assets/css/base.css):
22
+ *
23
+ * @import "tailwindcss";
24
+ * @source "../node_modules/@300codes/design-system/src/**\/*.{vue,ts}";
25
+ * @import "./tokens.css";
26
+ *
27
+ * Then register in nuxt.config.ts:
28
+ *
29
+ * css: ['~/assets/css/base.css']
30
+ */
31
+
32
+ :root {
33
+ /* ────────────────────────────────────────────────
34
+ * SimpleButton
35
+ * ──────────────────────────────────────────────── */
36
+
37
+ /* primary (default variant) */
38
+ --simpleButton-bg: theme(--color-primary);
39
+ --simpleButton-fg: theme(--color-primary-foreground);
40
+ --simpleButton-border: theme(--color-primary);
41
+ --simpleButton-bg-hover: theme(--color-primary-hover);
42
+ --simpleButton-fg-hover: theme(--color-primary-foreground);
43
+ --simpleButton-border-hover: theme(--color-primary-hover);
44
+ --simpleButton-border-width: theme(--spacing-px);
45
+ --simpleButton-ring: theme(--color-ring);
46
+ --simpleButton-radius: theme(--radius-base);
47
+ --simpleButton-px: theme(--spacing-6);
48
+ --simpleButton-py: theme(--spacing-1.5);
49
+ --simpleButton-min-h: theme(--spacing-14);
50
+ --simpleButton-font-size: theme(--text-base);
51
+ --simpleButton-font-weight: theme(--font-weight-semibold);
52
+ --simpleButton-gap: theme(--spacing-4);
53
+ --simpleButton-disabled-bg: theme(--color-disabled);
54
+ --simpleButton-disabled-fg: theme(--color-disabled-foreground);
55
+ --simpleButton-disabled-border: theme(--color-disabled);
56
+
57
+ /* secondary */
58
+ --simpleButton-secondary-bg: theme(--color-secondary);
59
+ --simpleButton-secondary-fg: theme(--color-secondary-foreground);
60
+ --simpleButton-secondary-border: theme(--color-secondary);
61
+ --simpleButton-secondary-bg-hover: theme(--color-secondary-hover);
62
+ --simpleButton-secondary-fg-hover: theme(--color-secondary-foreground-hover);
63
+ --simpleButton-secondary-border-hover: theme(--color-secondary-hover);
64
+ --simpleButton-secondary-ring: theme(--color-ring);
65
+ --simpleButton-secondary-disabled-bg: theme(--color-disabled);
66
+ --simpleButton-secondary-disabled-fg: theme(--color-disabled-foreground);
67
+ --simpleButton-secondary-disabled-border: theme(--color-disabled);
68
+
69
+ /* tertiary */
70
+ --simpleButton-tertiary-bg: transparent;
71
+ --simpleButton-tertiary-fg: theme(--color-tertiary-foreground);
72
+ --simpleButton-tertiary-border: transparent;
73
+ --simpleButton-tertiary-bg-hover: theme(--color-tertiary-hover);
74
+ --simpleButton-tertiary-fg-hover: theme(--color-tertiary-foreground);
75
+ --simpleButton-tertiary-border-hover: theme(--color-tertiary-hover);
76
+ --simpleButton-tertiary-ring: theme(--color-ring);
77
+ --simpleButton-tertiary-disabled-bg: transparent;
78
+ --simpleButton-tertiary-disabled-fg: theme(--color-disabled-foreground);
79
+ --simpleButton-tertiary-disabled-border: transparent;
80
+
81
+ /* sm */
82
+ --simpleButton-sm-px: theme(--spacing-4);
83
+ --simpleButton-sm-py: theme(--spacing-1);
84
+ --simpleButton-sm-min-h: theme(--spacing-10);
85
+ --simpleButton-sm-font-size: theme(--text-sm);
86
+ --simpleButton-sm-font-weight: theme(--font-weight-semibold);
87
+ --simpleButton-sm-gap: theme(--spacing-2.5);
88
+
89
+ /* ────────────────────────────────────────────────
90
+ * BaseLabel
91
+ * ──────────────────────────────────────────────── */
92
+
93
+ /* primary (default variant) */
94
+ --baseLabel-bg: theme(--color-primary);
95
+ --baseLabel-fg: theme(--color-primary-foreground);
96
+ --baseLabel-border: theme(--color-primary);
97
+ --baseLabel-border-width: theme(--spacing-px);
98
+ --baseLabel-bg-hover: theme(--color-primary-hover);
99
+ --baseLabel-border-hover: theme(--color-primary-hover);
100
+ --baseLabel-fg-hover: theme(--color-primary-foreground);
101
+ --baseLabel-ring: theme(--color-ring);
102
+ --baseLabel-radius: theme(--radius-base);
103
+ --baseLabel-px: theme(--spacing-2);
104
+ --baseLabel-py: theme(--spacing-0.5);
105
+ --baseLabel-min-h: theme(--spacing-6);
106
+ --baseLabel-font-size: theme(--text-xs);
107
+ --baseLabel-font-weight: theme(--font-weight-semibold);
108
+
109
+ /* secondary */
110
+ --baseLabel-secondary-bg: theme(--color-primary-foreground);
111
+ --baseLabel-secondary-fg: theme(--color-primary);
112
+ --baseLabel-secondary-border: theme(--color-primary);
113
+ --baseLabel-secondary-bg-hover: theme(--color-tertiary-hover);
114
+ --baseLabel-secondary-border-hover: theme(--color-primary-hover);
115
+ --baseLabel-secondary-fg-hover: theme(--color-secondary-foreground);
116
+ --baseLabel-secondary-ring: theme(--color-ring);
117
+
118
+ /* tertiary */
119
+ --baseLabel-tertiary-bg: transparent;
120
+ --baseLabel-tertiary-fg: theme(--color-tertiary-foreground);
121
+ --baseLabel-tertiary-border: transparent;
122
+ --baseLabel-tertiary-bg-hover: theme(--color-tertiary-hover);
123
+ --baseLabel-tertiary-border-hover: theme(--color-tertiary-hover);
124
+ --baseLabel-tertiary-fg-hover: theme(--color-primary);
125
+ --baseLabel-tertiary-ring: theme(--color-ring);
126
+
127
+ /* sm */
128
+ --baseLabel-sm-min-h: theme(--spacing-5);
129
+
130
+ /* ────────────────────────────────────────────────
131
+ * LabelInput
132
+ * ──────────────────────────────────────────────── */
133
+
134
+ --labelInput-fg: theme(--color-input-label);
135
+ --labelInput-fg-disabled: theme(--color-disabled-foreground);
136
+ --labelInput-font-size: 0.8125rem; /* md 13px */
137
+ --labelInput-sm-font-size: 0.6875rem; /* sm 11px */
138
+ --labelInput-lg-font-size: theme(--text-sm); /* lg 14px */
139
+ --labelInput-font-weight: theme(--font-weight-normal);
140
+ --labelInput-label-mb: theme(--spacing-1); /* md 4px */
141
+ --labelInput-sm-label-mb: theme(--spacing-0.5); /* sm 2px */
142
+ --labelInput-lg-label-mb: theme(--spacing-2); /* lg 8px */
143
+ --labelInput-message-mt: 0px; /* md 0 */
144
+ --labelInput-sm-message-mt: 0px; /* sm 0 */
145
+ --labelInput-lg-message-mt: 1px; /* lg 1px */
146
+ --labelInput-message-fg: theme(--color-error);
147
+ --labelInput-message-font-size: 0.8125rem; /* md 13px */
148
+ --labelInput-sm-message-font-size: 0.8125rem; /* sm 13px */
149
+ --labelInput-lg-message-font-size: theme(--text-sm); /* lg 14px */
150
+ --labelInput-status-valid-fg: theme(--color-success);
151
+ --labelInput-status-invalid-fg: theme(--color-error);
152
+ --labelInput-sm-status-size: theme(--spacing-6);
153
+ --labelInput-md-status-size: theme(--spacing-7);
154
+ --labelInput-lg-status-size: theme(--spacing-8);
155
+
156
+ /* ────────────────────────────────────────────────
157
+ * Input — shared (TextInput, SelectInput, Checkbox, Radio, Textarea)
158
+ * ──────────────────────────────────────────────── */
159
+
160
+ /* default state */
161
+ --input-bg: theme(--color-input-bg);
162
+ --input-fg: theme(--color-input-fg);
163
+ --input-border-color: theme(--color-input-border);
164
+ --input-border-width: theme(--spacing-px);
165
+ --input-placeholder-fg: theme(--color-input-placeholder);
166
+
167
+ /* hover */
168
+ --input-bg-hover: #f3f5f7;
169
+ --input-border-color-hover: theme(--color-input-border-hover);
170
+
171
+ /* focus */
172
+ --input-outline-width: theme(--outline-4);
173
+ --input-outline-offset: -4px;
174
+ --input-outline: theme(--color-outline);
175
+
176
+ /* invalid */
177
+ --input-border-color-invalid: theme(--color-error);
178
+
179
+ /* disabled */
180
+ --input-bg-disabled: theme(--color-input-bg-disabled);
181
+ --input-fg-disabled: theme(--color-input-fg-disabled);
182
+ --input-border-color-disabled: theme(--color-input-border-disabled);
183
+ --input-placeholder-fg-disabled: theme(--color-input-placeholder-disabled);
184
+
185
+ /* icon button */
186
+ --input-icon-bg: transparent;
187
+ --input-icon-fg: theme(--color-input-icon);
188
+ --input-icon-fg-hover: theme(--color-input-icon-hover);
189
+ --input-icon-bg-hover: theme(--color-input-icon-bg-hover);
190
+ --input-icon-outline: theme(--color-outline);
191
+ --input-icon-p: theme(--spacing-1);
192
+ --input-icon-radius: theme(--radius-full);
193
+
194
+ /* ────────────────────────────────────────────────
195
+ * TextInput — sizing
196
+ * ──────────────────────────────────────────────── */
197
+
198
+ /* md */
199
+ --input-h: theme(--spacing-12); /* desktop 48px */
200
+ --input-h-mobile: theme(--spacing-10); /* mobile 40px */
201
+ --input-px: theme(--spacing-3); /* desktop 12px */
202
+ --input-px-mobile: theme(--spacing-2.5); /* mobile 10px */
203
+ --input-py: theme(--spacing-2.5); /* desktop 10px */
204
+ --input-py-mobile: theme(--spacing-2); /* mobile 8px */
205
+ --input-radius: theme(--radius-md); /* desktop 6px */
206
+ --input-radius-mobile: theme(--radius-sm); /* mobile 4px */
207
+ --input-font-size: theme(--text-base); /* 16px */
208
+ --input-font-size-mobile: theme(--text-base); /* 16px */
209
+
210
+ /* sm */
211
+ --input-sm-h: theme(--spacing-10); /* desktop 40px */
212
+ --input-sm-h-mobile: theme(--spacing-10); /* mobile 40px */
213
+ --input-sm-px: theme(--spacing-2.5); /* desktop 10px */
214
+ --input-sm-px-mobile: theme(--spacing-2.5); /* mobile 10px */
215
+ --input-sm-py: theme(--spacing-2); /* desktop 8px */
216
+ --input-sm-py-mobile: theme(--spacing-2); /* mobile 8px */
217
+ --input-sm-radius: theme(--radius-sm); /* desktop 4px */
218
+ --input-sm-radius-mobile: theme(--radius-sm); /* mobile 4px */
219
+ --input-sm-font-size: theme(--text-sm); /* 14px */
220
+ --input-sm-font-size-mobile: theme(--text-sm); /* 14px */
221
+
222
+ /* lg */
223
+ --input-lg-h: theme(--spacing-14); /* desktop 56px */
224
+ --input-lg-h-mobile: theme(--spacing-12); /* mobile 48px */
225
+ --input-lg-px: theme(--spacing-4); /* desktop 16px */
226
+ --input-lg-px-mobile: theme(--spacing-3); /* mobile 12px */
227
+ --input-lg-py: theme(--spacing-3); /* desktop 12px */
228
+ --input-lg-py-mobile: theme(--spacing-2.5); /* mobile 10px */
229
+ --input-lg-radius: theme(--radius-lg); /* desktop 8px */
230
+ --input-lg-radius-mobile: theme(--radius-md); /* mobile 6px */
231
+ --input-lg-font-size: theme(--text-lg); /* 18px */
232
+ --input-lg-font-size-mobile: theme(--text-lg); /* 18px */
233
+
234
+ /* icon padding overrides */
235
+ --input-icon-pl: theme(--spacing-12);
236
+ --input-icon-pr: theme(--spacing-12);
237
+
238
+ /* ────────────────────────────────────────────────
239
+ * SelectInput — dropdown & mobile sheet
240
+ * ──────────────────────────────────────────────── */
241
+
242
+ /* trigger chevron */
243
+ --selectInput-chevron-fg: theme(--color-input-placeholder);
244
+
245
+ /* chevron size — per size × breakpoint */
246
+ --selectInput-chevron-size: theme(--spacing-6); /* md Desktop: 24px */
247
+ --selectInput-chevron-size-mobile: theme(--spacing-5); /* md Mobile: 20px */
248
+ --selectInput-sm-chevron-size: theme(--spacing-6); /* sm Desktop: 24px */
249
+ --selectInput-sm-chevron-size-mobile: theme(--spacing-5); /* sm Mobile: 20px */
250
+ --selectInput-lg-chevron-size: theme(--spacing-8); /* lg Desktop: 32px */
251
+ --selectInput-lg-chevron-size-mobile: theme(--spacing-7); /* lg Mobile: 28px */
252
+
253
+ /* desktop dropdown */
254
+ --selectInput-dropdown-bg: theme(--color-input-bg);
255
+ --selectInput-dropdown-border: theme(--color-input-border);
256
+ --selectInput-dropdown-border-width: theme(--spacing-px);
257
+ --selectInput-dropdown-radius: theme(--radius-md);
258
+ --selectInput-dropdown-max-h: 16rem;
259
+
260
+ /* dropdown vertical padding — per size */
261
+ --selectInput-dropdown-py: theme(--spacing-1); /* md Default: 4px */
262
+ --selectInput-sm-dropdown-py: theme(--spacing-1); /* sm = Default: 4px */
263
+ --selectInput-lg-dropdown-py: theme(--spacing-2); /* lg Comfort: 8px */
264
+
265
+ /* list spacing — gap between trigger and dropdown */
266
+ --selectInput-list-spacing: theme(--spacing-1); /* md: 4px */
267
+ --selectInput-sm-list-spacing: theme(--spacing-1); /* sm: 4px */
268
+ --selectInput-lg-list-spacing: theme(--spacing-2); /* lg: 8px */
269
+
270
+ /* option */
271
+ --selectInput-option-fg: theme(--color-input-fg);
272
+ --selectInput-option-hover-bg: theme(--color-input-bg-disabled);
273
+ --selectInput-option-selected-bg: theme(--color-outline);
274
+ --selectInput-option-selected-fg: theme(--color-primary);
275
+ --selectInput-option-py: theme(--spacing-3); /* 12px */
276
+ --selectInput-option-px: theme(--spacing-4); /* 16px */
277
+
278
+ /* mobile overlay (dialog::backdrop) */
279
+ --selectInput-overlay-bg: rgba(0, 0, 0, 0.5);
280
+
281
+ /* mobile sheet */
282
+ --selectInput-sheet-bg: theme(--color-input-bg);
283
+ --selectInput-sheet-max-h: 80vh;
284
+
285
+ /* sheet header */
286
+ --selectInput-sheet-header-py: theme(--spacing-3);
287
+ --selectInput-sheet-header-px: theme(--spacing-4);
288
+ --selectInput-sheet-header-fs: theme(--text-base);
289
+ --selectInput-sheet-header-fw: theme(--font-weight-semibold);
290
+ --selectInput-sheet-header-fg: theme(--color-input-fg);
291
+ --selectInput-sheet-header-border: theme(--color-input-border);
292
+
293
+ /* ────────────────────────────────────────────────
294
+ * CheckboxInput
295
+ * ──────────────────────────────────────────────── */
296
+
297
+ /* checked state */
298
+ --checkboxInput-checked-bg: #09865e;
299
+ --checkboxInput-checked-fg: theme(--color-white);
300
+ --checkboxInput-border-width: 1.5px;
301
+ --checkboxInput-border-color-disabled: #89979f;
302
+ --checkboxInput-checked-disabled-bg: #89979f;
303
+ --checkboxInput-outline-offset: -2px;
304
+
305
+ /* md (default) */
306
+ --checkboxInput-size: theme(--spacing-6); /* 24px */
307
+ --checkboxInput-icon-size: theme(--spacing-3.5); /* 14px */
308
+ --checkboxInput-radius: theme(--radius-md); /* 6px */
309
+ --checkboxInput-font-size: theme(--text-base); /* desktop 16px */
310
+ --checkboxInput-font-size-mobile: theme(--text-sm); /* mobile 14px */
311
+ --checkboxInput-spacing: theme(--spacing-4); /* 16px */
312
+
313
+ /* sm */
314
+ --checkboxInput-sm-size: theme(--spacing-5); /* 20px */
315
+ --checkboxInput-sm-icon-size: theme(--spacing-3); /* 12px */
316
+ --checkboxInput-sm-radius: theme(--radius-sm); /* 4px */
317
+ --checkboxInput-sm-font-size: theme(--text-sm); /* 14px */
318
+ --checkboxInput-sm-spacing: theme(--spacing-3); /* 12px */
319
+
320
+ /* lg */
321
+ --checkboxInput-lg-size: theme(--spacing-7); /* 28px */
322
+ --checkboxInput-lg-icon-size: theme(--spacing-4); /* 16px */
323
+ --checkboxInput-lg-radius: theme(--radius-lg); /* 8px */
324
+ --checkboxInput-lg-font-size: theme(--text-lg); /* 18px */
325
+ --checkboxInput-lg-spacing: theme(--spacing-5); /* 20px */
326
+
327
+ /* ────────────────────────────────────────────────
328
+ * RadioInput
329
+ * ──────────────────────────────────────────────── */
330
+
331
+ /* checked state */
332
+ --radioInput-checked-bg: theme(--color-white);
333
+ --radioInput-checked-border: #09865e;
334
+ --radioInput-checked-dot: #09865e;
335
+ --radioInput-checked-disabled-bg: theme(--color-white);
336
+ --radioInput-checked-disabled-dot: #89979f;
337
+
338
+ /* md (default) */
339
+ --radioInput-size: theme(--spacing-6); /* 24px */
340
+ --radioInput-dot-size: theme(--spacing-3.5); /* 14px */
341
+ --radioInput-font-size: theme(--text-base); /* desktop 16px */
342
+ --radioInput-font-size-mobile: theme(--text-sm); /* mobile 14px */
343
+ --radioInput-spacing: theme(--spacing-4); /* 16px */
344
+
345
+ /* sm */
346
+ --radioInput-sm-size: theme(--spacing-5); /* 20px */
347
+ --radioInput-sm-dot-size: theme(--spacing-3.5); /* 14px */
348
+ --radioInput-sm-font-size: theme(--text-sm); /* 14px */
349
+ --radioInput-sm-spacing: theme(--spacing-3); /* 12px */
350
+
351
+ /* lg */
352
+ --radioInput-lg-size: theme(--spacing-7); /* 28px */
353
+ --radioInput-lg-dot-size: theme(--spacing-4); /* 16px */
354
+ --radioInput-lg-font-size: theme(--text-lg); /* 18px */
355
+ --radioInput-lg-spacing: theme(--spacing-5); /* 20px */
356
+
357
+ /* ────────────────────────────────────────────────
358
+ * SearchInput
359
+ * ──────────────────────────────────────────────── */
360
+
361
+ --searchInput-bg: #f3f5f7;
362
+ --searchInput-border: theme(--color-input-border-hover);
363
+ --searchInput-bg-hover: theme(--color-white);
364
+ --searchInput-border-hover: theme(--color-input-fg);
365
+ --searchInput-radius: 3rem; /* 48px */
366
+
367
+ /* ────────────────────────────────────────────────
368
+ * BaseTooltip
369
+ * ──────────────────────────────────────────────── */
370
+
371
+ --baseTooltip-bg: #0e161b;
372
+ --baseTooltip-fg: theme(--color-white);
373
+ --baseTooltip-radius: theme(--radius-lg); /* 8px */
374
+ --baseTooltip-max-w: 12.25rem; /* 196px */
375
+ --baseTooltip-px: theme(--spacing-4); /* 16px */
376
+ --baseTooltip-py: theme(--spacing-4); /* 16px */
377
+ --baseTooltip-gap: theme(--spacing-4); /* 16px — text↔close */
378
+ --baseTooltip-font-size: theme(--text-xs); /* md 12px */
379
+ --baseTooltip-lg-font-size: theme(--text-sm); /* lg 14px */
380
+ --baseTooltip-arrow-half-w: theme(--spacing-1.5); /* md half-width 6px */
381
+ --baseTooltip-arrow-h: theme(--spacing-2); /* md arrow height 8px */
382
+ --baseTooltip-lg-arrow-half-w: theme(--spacing-3); /* lg half-width 12px */
383
+ --baseTooltip-lg-arrow-h: theme(--spacing-4); /* lg arrow height 16px */
384
+
385
+ /* ────────────────────────────────────────────────
386
+ * TabsList
387
+ * ──────────────────────────────────────────────── */
388
+
389
+ /* colors */
390
+ --tabsList-bg: theme(--color-input-bg);
391
+ --tabsList-fg: theme(--color-input-fg);
392
+ --tabsList-bg-hover: #f3f5f7;
393
+ --tabsList-fg-hover: theme(--color-input-fg);
394
+ --tabsList-active-bg: #5c6970;
395
+ --tabsList-active-fg: theme(--color-white);
396
+
397
+ /* focus ring */
398
+ --tabsList-outline-width: 4px;
399
+ --tabsList-outline-offset: -4px;
400
+ --tabsList-outline-color: theme(--color-outline);
401
+
402
+ /* shared */
403
+ --tabsList-radius: 3.5rem;
404
+ --tabsList-font-weight: theme(--font-weight-semibold);
405
+
406
+ /* md (default) */
407
+ --tabsList-gap: theme(--spacing-2); /* 8px */
408
+ --tabsList-px: theme(--spacing-7); /* 28px */
409
+ --tabsList-h: theme(--spacing-10); /* 40px */
410
+ --tabsList-font-size: theme(--text-sm);
411
+
412
+ /* lg */
413
+ --tabsList-lg-gap: theme(--spacing-4); /* 16px */
414
+ --tabsList-lg-px: theme(--spacing-9); /* 36px */
415
+ --tabsList-lg-h: theme(--spacing-14); /* 56px */
416
+ --tabsList-lg-font-size: theme(--text-base);
417
+ }
@@ -0,0 +1 @@
1
+ export type IconSize = '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'auto';