Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import { Buffer } from 'buffer'
window.Buffer = Buffer
</script>
<link rel="stylesheet" href="./packages/design-system/src/styles/stylesWrapper.scss" />
<style>
html,
body {
Expand Down Expand Up @@ -96,7 +95,7 @@ <h2>Your browser is not supported</h2>
</div>
</div>
<button
class="oc-button oc-button-primary oc-button-primary-filled oc-rounded"
class="oc-button oc-button-primary oc-button-primary-filled rounded-sm"
onclick="forceOldBrowser()"
>
I want to continue anyway
Expand Down
2 changes: 1 addition & 1 deletion packages/design-system/build/build-tokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const sd = new StyleDictionary({
buildPath: 'src/assets/tokens/',
files: [
{
destination: 'ods.scss',
destination: 'ods.css',
format: 'format/ods/scss',
filter: ({ filePath }) => filePath.includes('/ods/')
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ export default {
format: (dictionary) => {
const props = sortProps(dictionary.allTokens)
const data = [
...props.map((p) => `$${p.name}: ${p.value};`),
'',
':host, :root {',
...props.map((p) => ` --${p.name}: #{$${p.name}};`),
...props.map((p) => ` --${p.name}: ${p.value};`),
'}',
''
].join('\n')
Expand Down
24 changes: 2 additions & 22 deletions packages/design-system/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { generateJsonMetaData } from './generateJsonMetaData'
import tailwindcss from '@tailwindcss/vite'

const projectRootDir = searchForWorkspaceRoot(process.cwd())
const stripScssMarker = '/* STYLES STRIP IMPORTS MARKER */'

export default defineConfig({
title: 'OpenCloud Design System',
Expand Down Expand Up @@ -44,7 +43,8 @@ export default defineConfig({
scss: {
additionalData: `
@use "sass:math";
@import "${projectRootDir}/packages/design-system/src/styles/styles";${stripScssMarker};
@use "sass:string";
@use "sass:meta";
`,
silenceDeprecations: ['legacy-js-api', 'import']
}
Expand All @@ -53,26 +53,6 @@ export default defineConfig({
plugins: [
tailwindcss(),
generateJsonMetaData(),
{
name: '@opencloud-eu/vite-plugin-strip-css',
transform(src, id) {
if (id.endsWith('.vue') && !id.includes('node_modules') && src.includes('@extend')) {
console.warn(
'You are using @extend in your component. This is likely not working in your styles. Please use mixins instead.',
id.replace(`${projectRootDir}/`, '')
)
}
if (id.includes('lang.scss')) {
const split = src.split(stripScssMarker)
const newSrc = split[split.length - 1]

return {
code: newSrc,
map: null
}
}
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sad to see this go... 😍 🎉

viteStaticCopy({
targets: (() => {
return [
Expand Down
26 changes: 24 additions & 2 deletions packages/design-system/src/components/OcCheckbox/OcCheckbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,28 @@ const keydownEnter = (event: KeyboardEvent) => {
</style>
<style lang="scss">
.oc-checkbox {
$internal-form-checkbox-image: 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A' !default;
$internal-form-checkbox-indeterminate-image: 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E' !default;

@function str-replace($string, $search, $replace: '') {
$index: string.index($string, $search);

@if $index {
@return string.slice($string, 1, $index - 1) + $replace +
str-replace(string.slice($string, $index + string.length($search)), $search, $replace);
}

@return $string;
}

@mixin svg-fill($src, $color-default, $color-new) {
$replace-src: str-replace($src, $color-default, $color-new) !default;
$replace-src: str-replace($replace-src, '#', '%23');
$replace-src: string.quote($replace-src);

background-image: url($replace-src);
}

&-checked,
:checked {
@include svg-fill($internal-form-checkbox-image, '#000', '#000');
Expand All @@ -116,14 +138,14 @@ const keydownEnter = (event: KeyboardEvent) => {
}

&:disabled:checked {
@include svg-fill($internal-form-checkbox-image, '#000', $form-radio-disabled-icon-color);
@include svg-fill($internal-form-checkbox-image, '#000', var(--oc-role-on-surface-variant));
Copy link

Copilot AI Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is using variables like $form-radio-disabled-icon-color in comments but then using hardcoded CSS custom property values. This creates inconsistency and makes it harder to maintain. Consider defining these values consistently either as SCSS variables or CSS custom properties throughout the component.

Copilot uses AI. Check for mistakes.
}

&:disabled:indeterminate {
@include svg-fill(
$internal-form-checkbox-indeterminate-image,
'#000',
$form-radio-disabled-icon-color
var(--oc-role-on-surface-variant)
Copy link

Copilot AI Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is using variables like $form-radio-disabled-icon-color in comments but then using hardcoded CSS custom property values. This creates inconsistency and makes it harder to maintain. Consider defining these values consistently either as SCSS variables or CSS custom properties throughout the component.

Copilot uses AI. Check for mistakes.
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div :class="$attrs.class">
<slot name="label">
<label class="oc-label" :for="id">
<label class="inline-block mb-0.5" :for="id">
{{ label }}
<span v-if="requiredMark" class="text-role-on-error" aria-hidden="true">*</span>
</label>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`OcDatePicker > renders 1`] = `
"<div class="oc-date-picker"><label class="oc-label" for="oc-textinput-1">Datepicker label
"<div class="oc-date-picker"><label class="inline-block mb-0.5" for="oc-textinput-1">Datepicker label
<!--v-if-->
</label>
<div class="relative">
<!--v-if--> <input id="oc-textinput-1" aria-invalid="false" class="oc-text-input oc-input rounded-sm focus:border focus:border-role-surface placeholder:opacity-100 disabled:cursor-not-allowed" type="date" value="">
<!--v-if--> <input id="oc-textinput-1" aria-invalid="false" class="oc-text-input oc-input" type="date" value="">
<!--v-if-->
</div>
<div class="oc-text-input-message flex align-center text-sm mt-1 min-h-4.5">
Expand Down
24 changes: 24 additions & 0 deletions packages/design-system/src/components/OcDrop/OcDrop.vue
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,30 @@ watch(
.oc-drop {
@apply w-xs max-w-full;
}

.oc-bottom-drawer li a,
.oc-bottom-drawer li .item-has-switch,
.oc-bottom-drawer li button:not([role='switch']),
.oc-drop li a,
.oc-drop li button:not([role='switch']),
.oc-drop li .item-has-switch {
@apply p-2 w-full;
}

.oc-bottom-drawer li,
.oc-drop li {
@apply mb-1;
}

.oc-bottom-drawer li:first-child,
.oc-drop li:first-child {
@apply mt-0;
}

.oc-bottom-drawer li:last-child,
.oc-drop li:last-child {
@apply mb-0;
}
}

.tippy-box[data-theme~='none'] {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div :class="$attrs.class">
<slot name="label">
<label class="oc-label" :for="id">
<label class="inline-block mb-0.5" :for="id">
{{ label }}
<span v-if="requiredMark" class="text-role-on-error" aria-hidden="true">*</span>
</label>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
class="oc-fade-in flex flex-wrap oc-notification-message shadow-md/20 rounded-sm break-keep bg-role-surface"
class="flex flex-wrap oc-notification-message shadow-md/20 rounded-sm break-keep bg-role-surface motion-safe:animate-fade-in"
:class="classes"
>
<div class="flex flex-wrap items-center flex-1" :role="role" :aria-live="ariaLive">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div>
<label v-if="!labelHidden" :aria-hidden="true" :for="id" class="oc-label">
<label v-if="!labelHidden" :aria-hidden="true" :for="id" class="inline-block mb-0.5">
{{ label }}
<span v-if="requiredMark" class="text-role-on-error" aria-hidden="true">*</span>
</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ describe('OcTableCell', () => {
})

expect(wrapper.element.tagName).toBe('TH')
expect(wrapper.attributes('class')).toContain('oc-table-cell-align-right')
expect(wrapper.attributes('class')).toContain('oc-table-cell-align-bottom')
expect(wrapper.attributes('class')).toContain('oc-table-cell-width-shrink')
expect(wrapper.attributes('class')).toContain('text-right')
expect(wrapper.attributes('class')).toContain('align-bottom')
expect(wrapper.attributes('class')).toContain('w-px')
expect(wrapper.html()).toMatchSnapshot()
})
})
58 changes: 18 additions & 40 deletions packages/design-system/src/components/OcTableCell/OcTableCell.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
<template>
<component :is="type" :class="cellClasses" @click="emit('click', $event)">
<component
:is="type"
class="oc-table-cell"
:class="{
'break-all': wrap === 'break',
'whitespace-nowrap': wrap === 'nowrap',
'overflow-visible max-w-0': wrap === 'truncate',
'text-left': alignH === 'left',
'text-right': alignH === 'right',
'text-center': alignH === 'center',
'align-top': alignV === 'top',
'align-middle': alignV === 'middle',
'align-bottom': alignV === 'bottom',
'w-px': width === 'shrink',
'min-w-38': width === 'expand'
}"
@click="emit('click', $event)"
>
<slot />
</component>
</template>

<script setup lang="ts">
import { computed } from 'vue'

export interface Props {
alignH?: 'left' | 'center' | 'right'
alignV?: 'top' | 'middle' | 'bottom'
Expand All @@ -24,19 +39,6 @@ const {
} = defineProps<Props>()

const emit = defineEmits(['click'])

const cellClasses = computed(() => {
const classes = [
'oc-table-cell',
`oc-table-cell-align-${alignH}`,
`oc-table-cell-align-${alignV}`,
`oc-table-cell-width-${width}`
]
if (wrap) {
classes.push(`oc-text-${wrap}`)
}
return classes
})
</script>
<style>
@reference '@opencloud-eu/design-system/tailwind';
Expand All @@ -45,29 +47,5 @@ const cellClasses = computed(() => {
.oc-table-cell {
@apply px-2 relative;
}
.oc-table-cell-align-left {
@apply text-left;
}
.oc-table-cell-align-center {
@apply text-center;
}
.oc-table-cell-align-right {
@apply text-right;
}
.oc-table-cell-align-top {
@apply align-top;
}
.oc-table-cell-align-middle {
@apply align-middle;
}
.oc-table-cell-align-bottom {
@apply align-bottom;
}
.oc-table-cell-width-shrink {
@apply w-px;
}
.oc-table-cell-width-expand {
@apply min-w-38;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`OcTableCell > Uses correct element 1`] = `"<th class="oc-table-cell oc-table-cell-align-right oc-table-cell-align-bottom oc-table-cell-width-shrink">Hello world!</th>"`;
exports[`OcTableCell > Uses correct element 1`] = `"<th class="oc-table-cell text-right align-bottom w-px">Hello world!</th>"`;
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ describe('OcTextInput', () => {
describe('required mark', () => {
it('should be displayed', () => {
const wrapper = getShallowWrapper({ requiredMark: true })
expect(wrapper.find('.oc-label span').text()).toContain('*')
expect(wrapper.find('label span').text()).toContain('*')
})
})
})
17 changes: 13 additions & 4 deletions packages/design-system/src/components/OcTextInput/OcTextInput.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div :class="$attrs.class">
<slot name="label">
<label class="oc-label" :for="id">
<label class="inline-block mb-0.5" :for="id">
{{ label }}
<span v-if="requiredMark" class="text-role-on-error" aria-hidden="true">*</span>
</label>
Expand All @@ -14,7 +14,7 @@
v-bind="additionalAttributes"
ref="inputRef"
:aria-invalid="ariaInvalid"
class="oc-text-input oc-input rounded-sm focus:border focus:border-role-surface placeholder:opacity-100 disabled:cursor-not-allowed"
class="oc-text-input oc-input"
:class="{
'oc-text-input-danger border-role-error': !!showErrorMessage,
'pl-6': !!readOnly,
Expand Down Expand Up @@ -347,8 +347,17 @@ watch(
@reference '@opencloud-eu/design-system/tailwind';

@layer components {
.oc-text-input:focus {
@apply outline-2 outline-role-outline;
.oc-input {
@apply inline-block align-middle text-role-on-surface bg-role-surface w-full max-w-full rounded-sm p-1.5 leading-4 border border-role-outline outline-0 overflow-visible appearance-none;
}
.oc-input:focus {
@apply border border-role-surface outline-2 outline-role-outline;
}
.oc-input:disabled {
@apply bg-role-surface-container cursor-not-allowed;
}
.oc-input::placeholder {
@apply text-role-on-surface opacity-100;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`OcTextInput > password input field > password policy > displays error state if password does not match criteria 1`] = `
"<div class=""><label class="oc-label" for="oc-textinput-20">test
"<div class=""><label class="inline-block mb-0.5" for="oc-textinput-20">test
<!--v-if-->
</label>
<div class="relative">
<!--v-if-->
<div class="oc-text-input-password-wrapper flex flex-row border rounded-sm border-role-outline"><input id="oc-textinput-20" aria-invalid="false" class="oc-text-input oc-input rounded-sm focus:border focus:border-role-surface placeholder:opacity-100 disabled:cursor-not-allowed grow-2 border-0 focus:border-0 focus:outline-0" type="password"> <button type="button" aria-label="Show password" class="oc-button-secondary oc-button-raw oc-button-secondary-raw gap-2 justify-center text-sm min-h-3 oc-button inline-flex cursor-pointer disabled:opacity-60 disabled:cursor-default oc-text-input-show-password-toggle px-2">
<div class="oc-text-input-password-wrapper flex flex-row border rounded-sm border-role-outline"><input id="oc-textinput-20" aria-invalid="false" class="oc-text-input oc-input grow-2 border-0 focus:border-0 focus:outline-0" type="password"> <button type="button" aria-label="Show password" class="oc-button-secondary oc-button-raw oc-button-secondary-raw gap-2 justify-center text-sm min-h-3 oc-button inline-flex cursor-pointer disabled:opacity-60 disabled:cursor-default oc-text-input-show-password-toggle px-2">
<!--v-if-->
<!-- @slot Content of the button --> <span class="oc-icon box-content size-4"><svg data-testid="inline-svg-stub" src="icons/eye-fill.svg" transform-source="(svg) => {
if (__props.accessibleLabel !== &quot;&quot;) {
Expand Down Expand Up @@ -54,12 +54,12 @@ exports[`OcTextInput > password input field > password policy > displays error s
`;

exports[`OcTextInput > password input field > password policy > displays success state if password matches criteria 1`] = `
"<div class=""><label class="oc-label" for="oc-textinput-21">test
"<div class=""><label class="inline-block mb-0.5" for="oc-textinput-21">test
<!--v-if-->
</label>
<div class="relative">
<!--v-if-->
<div class="oc-text-input-password-wrapper flex flex-row border rounded-sm border-role-outline"><input id="oc-textinput-21" aria-invalid="false" class="oc-text-input oc-input rounded-sm focus:border focus:border-role-surface placeholder:opacity-100 disabled:cursor-not-allowed grow-2 border-0 focus:border-0 focus:outline-0" type="password"> <button type="button" aria-label="Show password" class="oc-button-secondary oc-button-raw oc-button-secondary-raw gap-2 justify-center text-sm min-h-3 oc-button inline-flex cursor-pointer disabled:opacity-60 disabled:cursor-default oc-text-input-show-password-toggle px-2">
<div class="oc-text-input-password-wrapper flex flex-row border rounded-sm border-role-outline"><input id="oc-textinput-21" aria-invalid="false" class="oc-text-input oc-input grow-2 border-0 focus:border-0 focus:outline-0" type="password"> <button type="button" aria-label="Show password" class="oc-button-secondary oc-button-raw oc-button-secondary-raw gap-2 justify-center text-sm min-h-3 oc-button inline-flex cursor-pointer disabled:opacity-60 disabled:cursor-default oc-text-input-show-password-toggle px-2">
<!--v-if-->
<!-- @slot Content of the button --> <span class="oc-icon box-content size-4"><svg data-testid="inline-svg-stub" src="icons/eye-fill.svg" transform-source="(svg) => {
if (__props.accessibleLabel !== &quot;&quot;) {
Expand Down
Loading