From 7389fab815f1c15e233e475282c2591d3379a068 Mon Sep 17 00:00:00 2001 From: Guilherme Santana Date: Mon, 13 Apr 2026 16:55:21 -0300 Subject: [PATCH] feat: add BoxGridSelection component and update semantic background tokens --- .../stories/core/BoxGridSelection.stories.js | 197 ++++++++++++++++++ .../src/tailwind/semantic-colors-plugin.js | 40 ++-- .../theme/src/tokens/semantic/backgrounds.js | 16 +- packages/webkit/package.json | 1 + .../box-grid-selection/box-grid-selection.vue | 118 +++++++++++ .../box-grid-selection/package.json | 11 + .../src/core/card/card-box/card-box.vue | 6 +- 7 files changed, 363 insertions(+), 26 deletions(-) create mode 100644 apps/storybook/src/stories/core/BoxGridSelection.stories.js create mode 100644 packages/webkit/src/components/box-grid-selection/box-grid-selection.vue create mode 100644 packages/webkit/src/components/box-grid-selection/package.json diff --git a/apps/storybook/src/stories/core/BoxGridSelection.stories.js b/apps/storybook/src/stories/core/BoxGridSelection.stories.js new file mode 100644 index 00000000..2d36d3e5 --- /dev/null +++ b/apps/storybook/src/stories/core/BoxGridSelection.stories.js @@ -0,0 +1,197 @@ +import BoxGridSelection from '@aziontech/webkit/box-grid-selection' +import Tag from '@aziontech/webkit/tag' + +export default { + title: 'Core/BoxGridSelection', + component: BoxGridSelection, + tags: ['autodocs'], + argTypes: { + modelValue: { + control: 'text', + description: 'Currently selected item value (supports v-model)' + }, + items: { + control: 'object', + description: 'Array of items with {value, icon, description, disabled?, ariaLabel?}' + }, + disabled: { + control: 'boolean', + description: 'Disables all selections' + }, + columns: { + control: { type: 'number', min: 1, max: 4 }, + description: 'Number of grid columns (1-4, default: 3)' + } + } +} + +const planItems = [ + { + value: 'hobby', + icon: 'pi pi-sparkles', + description: 'For learning and small personal projects.', + tag: 'Hobby Plan' + }, + { + value: 'pro', + icon: 'pi pi-chart-line', + description: 'For professional or commercial applications.', + tag: 'Pro Plan' + }, + { + value: 'scale', + icon: 'pi pi-file-check', + description: 'For businesses requiring advanced security and compliance.', + tag: 'Scale Plan' + } +] + +const basicItems = [ + { value: 'option1', icon: 'pi pi-check', description: 'First option description' }, + { value: 'option2', icon: 'pi pi-times', description: 'Second option description' }, + { value: 'option3', icon: 'pi pi-star', description: 'Third option description' } +] + +export const PlanSelection = { + args: { + modelValue: 'hobby', + columns: 3, + items: planItems + }, + render: (args) => ({ + components: { BoxGridSelection, Tag }, + setup() { + return { args } + }, + template: ` + + + + ` + }) +} + +export const Default = { + args: { + modelValue: 'option1', + columns: 3, + items: basicItems + } +} + +export const WithTwoColumns = { + args: { + modelValue: 'option1', + columns: 2, + items: [ + { value: 'option1', icon: 'pi pi-desktop', description: 'Desktop application' }, + { value: 'option2', icon: 'pi pi-mobile', description: 'Mobile application' } + ] + } +} + +export const WithFourColumns = { + args: { + modelValue: 'option2', + columns: 4, + items: [ + { value: 'option1', icon: 'pi pi-cloud', description: 'Cloud storage' }, + { value: 'option2', icon: 'pi pi-database', description: 'Database service' }, + { value: 'option3', icon: 'pi pi-server', description: 'Server hosting' }, + { value: 'option4', icon: 'pi pi-shield', description: 'Security suite' } + ] + } +} + +export const Disabled = { + args: { + modelValue: 'option1', + columns: 3, + items: basicItems, + disabled: true + } +} + +export const WithDisabledItem = { + args: { + modelValue: 'option1', + columns: 3, + items: [ + { value: 'option1', icon: 'pi pi-check', description: 'Available option' }, + { value: 'option2', icon: 'pi pi-times', description: 'Unavailable option', disabled: true }, + { value: 'option3', icon: 'pi pi-star', description: 'Available option' } + ] + } +} + +export const Interactive = { + args: { + modelValue: 'hobby', + columns: 3, + items: planItems + }, + render: (args) => ({ + components: { BoxGridSelection, Tag }, + data() { + return { + selectedValue: 'hobby' + } + }, + methods: { + handleChange(item) { + console.log('Selected:', item) + } + }, + template: ` +
+ + + +

+ Selected plan: {{ selectedValue }} +

+
+ ` + }) +} + +export const WithoutIcons = { + args: { + modelValue: 'basic', + columns: 3, + items: [ + { value: 'basic', description: 'Basic tier with essential features' }, + { value: 'standard', description: 'Standard tier with more features' }, + { value: 'premium', description: 'Premium tier with all features' } + ] + } +} + +export const SingleColumn = { + args: { + modelValue: 'option1', + columns: 1, + items: [ + { value: 'option1', icon: 'pi pi-upload', description: 'Upload files from your computer' }, + { value: 'option2', icon: 'pi pi-cloud-upload', description: 'Import from cloud storage' }, + { value: 'option3', icon: 'pi pi-link', description: 'Import from URL' } + ] + } +} diff --git a/packages/theme/src/tailwind/semantic-colors-plugin.js b/packages/theme/src/tailwind/semantic-colors-plugin.js index fd4e40eb..12c98f0c 100644 --- a/packages/theme/src/tailwind/semantic-colors-plugin.js +++ b/packages/theme/src/tailwind/semantic-colors-plugin.js @@ -18,11 +18,11 @@ // Lazy-require to avoid hard dependency for consumers const plugin = (() => { try { - return require('tailwindcss/plugin'); + return require('tailwindcss/plugin') } catch { - return (handler) => handler; + return (handler) => handler } -})(); +})() /** * Generate semantic color utilities @@ -45,8 +45,8 @@ export const semanticColors = () => { '.text-warning': { color: 'var(--text-warning)' }, '.text-warningHover': { color: 'var(--text-warningHover)' }, '.text-success': { color: 'var(--text-success)' }, - '.text-successHover': { color: 'var(--text-successHover)' }, - }; + '.text-successHover': { color: 'var(--text-successHover)' } + } const bgColors = { '.bg-surfaceRaised': { 'background-color': 'var(--background-surfaceRaised)' }, @@ -62,7 +62,8 @@ export const semanticColors = () => { '.bg-backdrop': { 'background-color': 'var(--background-backdrop)' }, '.bg-primary': { 'background-color': 'var(--background-primary)' }, '.bg-primaryHover': { 'background-color': 'var(--background-primaryHover)' }, - }; + '.bg-primary-mask': { 'background-color': 'var(--background-primaryMask)' } + } const borderColors = { '.border-default': { 'border-color': 'var(--border-default)' }, @@ -77,14 +78,23 @@ export const semanticColors = () => { '.border-primary': { 'border-color': 'var(--border-primary)' }, '.border-primaryHover': { 'border-color': 'var(--border-primaryHover)' }, '.border-accent': { 'border-color': 'var(--border-accent)' }, - '.border-accentHover': { 'border-color': 'var(--border-accentHover)' }, - }; + '.border-accentHover': { 'border-color': 'var(--border-accentHover)' } + } - const variants = ['responsive', 'hover', 'dark', 'before', 'after', 'focus', 'active', 'disabled']; - addUtilities(textColors, variants); - addUtilities(bgColors, variants); - addUtilities(borderColors, variants); - }); -}; + const variants = [ + 'responsive', + 'hover', + 'dark', + 'before', + 'after', + 'focus', + 'active', + 'disabled' + ] + addUtilities(textColors, variants) + addUtilities(bgColors, variants) + addUtilities(borderColors, variants) + }) +} -export default semanticColors; +export default semanticColors diff --git a/packages/theme/src/tokens/semantic/backgrounds.js b/packages/theme/src/tokens/semantic/backgrounds.js index 8011ebd2..66c36f57 100644 --- a/packages/theme/src/tokens/semantic/backgrounds.js +++ b/packages/theme/src/tokens/semantic/backgrounds.js @@ -4,7 +4,7 @@ * Generated from figma-reference-tokens-studio. */ -import { tokenRef } from '../build/refs.js'; +import { tokenRef } from '../build/refs.js' export const backgroundSemantic = { light: { @@ -20,7 +20,8 @@ export const backgroundSemantic = { warning: tokenRef('primitives.yellow.200'), backdrop: tokenRef('#00000040'), primaryHover: tokenRef('brand.primary.primary-600'), - primary: tokenRef('brand.primary.primary-500') + primary: tokenRef('brand.primary.primary-500'), + primaryMask: tokenRef('#FE601F29') }, dark: { surfaceRaised: tokenRef('brand.surfaces.surface-800'), @@ -35,10 +36,11 @@ export const backgroundSemantic = { warning: tokenRef('primitives.yellow.800'), backdrop: tokenRef('#00000040'), primaryHover: tokenRef('brand.primary.primary-400'), - primary: tokenRef('brand.primary.primary-500') - }, -}; + primary: tokenRef('brand.primary.primary-500'), + primaryMask: tokenRef('#FE601F29') + } +} export default { - backgroundSemantic, -}; + backgroundSemantic +} diff --git a/packages/webkit/package.json b/packages/webkit/package.json index 8703d4cd..1ae9bb40 100644 --- a/packages/webkit/package.json +++ b/packages/webkit/package.json @@ -73,6 +73,7 @@ "./empty-results-block": "./src/components/empty-results-block/empty-results-block.vue", "./resizable-splitter": "./src/components/resizable-splitter/resizable-splitter.vue", "./overline": "./src/components/overline/overline.vue", + "./box-grid-selection": "./src/components/box-grid-selection/box-grid-selection.vue", "./accordion": "./src/core/primevue/accordion/accordion.vue", "./accordion-tab": "./src/core/primevue/accordion-tab/accordion-tab.vue", "./avatar": "./src/core/primevue/avatar/avatar.vue", diff --git a/packages/webkit/src/components/box-grid-selection/box-grid-selection.vue b/packages/webkit/src/components/box-grid-selection/box-grid-selection.vue new file mode 100644 index 00000000..9574604b --- /dev/null +++ b/packages/webkit/src/components/box-grid-selection/box-grid-selection.vue @@ -0,0 +1,118 @@ + + + diff --git a/packages/webkit/src/components/box-grid-selection/package.json b/packages/webkit/src/components/box-grid-selection/package.json new file mode 100644 index 00000000..fc41c090 --- /dev/null +++ b/packages/webkit/src/components/box-grid-selection/package.json @@ -0,0 +1,11 @@ +{ + "main": "./box-grid-selection.vue", + "module": "./box-grid-selection.vue", + "types": "./box-grid-selection.vue.d.ts", + "browser": { + "./sfc": "./box-grid-selection.vue" + }, + "sideEffects": [ + "*.vue" + ] +} diff --git a/packages/webkit/src/core/card/card-box/card-box.vue b/packages/webkit/src/core/card/card-box/card-box.vue index 8fecf5da..02785963 100644 --- a/packages/webkit/src/core/card/card-box/card-box.vue +++ b/packages/webkit/src/core/card/card-box/card-box.vue @@ -1,7 +1,5 @@