Schneller
@@ -266,7 +266,7 @@ export const Multipart: Story = {
-
+
Sample Product
140 x 90 mm bis B5 (250 x 176 mm)
@@ -304,7 +304,7 @@ export const Multipart: Story = {
-
+
diff --git a/packages/documentation/src/stories/components/forms/input/input.snapshot.stories.ts b/packages/documentation/src/stories/components/forms/input/input.snapshot.stories.ts
index 8eb3453ce4..1b4d74221a 100644
--- a/packages/documentation/src/stories/components/forms/input/input.snapshot.stories.ts
+++ b/packages/documentation/src/stories/components/forms/input/input.snapshot.stories.ts
@@ -66,7 +66,7 @@ function renderInputSnapshot(_args: Args, context: StoryContext) {
(context.args.type === 'text' || context.args.type === 'password')),
)
.map((args: Args) => {
- context.id = `a-${crypto.randomUUID()}`;
+ context.id = `${bg}-${crypto.randomUUID()}`;
return html`
${meta.render?.({ ...context.args, ...args }, context)}
`;
})}
diff --git a/packages/documentation/src/stories/components/forms/input/input.stories.ts b/packages/documentation/src/stories/components/forms/input/input.stories.ts
index 732f001126..694e08502e 100644
--- a/packages/documentation/src/stories/components/forms/input/input.stories.ts
+++ b/packages/documentation/src/stories/components/forms/input/input.stories.ts
@@ -183,7 +183,7 @@ export default meta;
type Story = StoryObj;
function render(args: Args, context: StoryContext) {
- const id = `ExampleTextarea_${context.name}`;
+ const id = context.id ?? `ExampleTextarea_${context.name}`;
const classes = [
'form-control',
args.size,
diff --git a/packages/documentation/src/stories/components/forms/radio/radio.snapshot.stories.ts b/packages/documentation/src/stories/components/forms/radio/radio.snapshot.stories.ts
index 78965fb654..66012d5436 100644
--- a/packages/documentation/src/stories/components/forms/radio/radio.snapshot.stories.ts
+++ b/packages/documentation/src/stories/components/forms/radio/radio.snapshot.stories.ts
@@ -39,7 +39,7 @@ export const Radio: Story = {
// remove disabled & validated examples
.filter((args: Args) => !(args.disabled && args.validation !== 'null'))
.map((args: Args) => {
- context.id = `a-${crypto.randomUUID()}`;
+ context.id = `${bg}-${crypto.randomUUID()}`;
return meta.render?.({ ...context.args, ...args }, context);
})}
diff --git a/packages/documentation/src/stories/components/forms/radio/radio.stories.ts b/packages/documentation/src/stories/components/forms/radio/radio.stories.ts
index d3e594e2bc..365299ed58 100644
--- a/packages/documentation/src/stories/components/forms/radio/radio.stories.ts
+++ b/packages/documentation/src/stories/components/forms/radio/radio.stories.ts
@@ -119,7 +119,7 @@ const meta: MetaComponent = {
function render(args: Args, context: StoryContext) {
const [_, updateArgs] = useArgs();
- const id = `${context.viewMode}_${context.name.replace(/\s/g, '-')}_ExampleRadio`;
+ const id = context.id ?? `${context.viewMode}_${context.name.replace(/\s/g, '-')}_ExampleRadio`;
const classes = ['form-check-input', args.validation].filter(c => c && c !== 'null').join(' ');
const groupClasses = ['form-check', args.size].filter(c => c && c !== 'null').join(' ');
diff --git a/packages/documentation/src/stories/components/forms/slider/slider.snapshot.stories.ts b/packages/documentation/src/stories/components/forms/slider/slider.snapshot.stories.ts
index 9053933684..1be11c3164 100644
--- a/packages/documentation/src/stories/components/forms/slider/slider.snapshot.stories.ts
+++ b/packages/documentation/src/stories/components/forms/slider/slider.snapshot.stories.ts
@@ -49,7 +49,7 @@ export const Slider: Story = {
hiddenLabel: [true],
}),
].map((args: Args) => {
- context.id = `a-${crypto.randomUUID()}`;
+ context.id = `${bg}-${crypto.randomUUID()}`;
return meta.render?.({ ...context.args, ...args }, context);
})}
diff --git a/packages/documentation/src/stories/components/forms/slider/slider.stories.ts b/packages/documentation/src/stories/components/forms/slider/slider.stories.ts
index a37f9bd2ef..85974e8ef5 100644
--- a/packages/documentation/src/stories/components/forms/slider/slider.stories.ts
+++ b/packages/documentation/src/stories/components/forms/slider/slider.stories.ts
@@ -165,7 +165,7 @@ type Story = StoryObj;
function render(args: Args, context: StoryContext) {
const [_, updateArgs] = useArgs();
- const id = `${context.viewMode}_${context.name.replace(/\s/g, '-')}_ExampleRange`;
+ const id = context.id ?? `${context.viewMode}_${context.name.replace(/\s/g, '-')}_ExampleRange`;
const classes = ['form-range', args.validation].filter(c => c && c !== 'null').join(' ');
const useAriaLabel = args.hiddenLabel;
@@ -200,7 +200,9 @@ function render(args: Args, context: StoryContext) {
if (args.showValue === 'text') {
valueElement = html`
${args.value}
`;
} else if (args.showValue === 'input') {
- const inputId = `${context.viewMode}_${context.name.replace(/\s/g, '-')}_ExampleRangeInput`;
+ const inputId = context.id
+ ? `${context.id}_input`
+ : `${context.viewMode}_${context.name.replace(/\s/g, '-')}_ExampleRangeInput`;
valueElement = [
html`
`,
diff --git a/packages/documentation/src/stories/components/forms/switch/switch.snapshot.stories.ts b/packages/documentation/src/stories/components/forms/switch/switch.snapshot.stories.ts
index 5d34b3bc3b..b550dfdd84 100644
--- a/packages/documentation/src/stories/components/forms/switch/switch.snapshot.stories.ts
+++ b/packages/documentation/src/stories/components/forms/switch/switch.snapshot.stories.ts
@@ -16,29 +16,30 @@ export const Switch: Story = {
render: (_args: Args, context: StoryContext) => {
const longerText =
'Longa etikedo kiu plej versajne ne taugas sur unu linio kaj tial devas esti envolvita. Kaj nur por esti sur la sekura flanko, ni simple aldonu unu plian tre sencelan frazon ci tie. Vi neniam scias...';
- const templateVariants = bombArgs({
- labelPosition: ['before', 'after'],
- label: ['Notifications', longerText],
- hiddenLabel: [false],
- checked: [false, true],
- disabled: [false, true],
- validation: ['null', 'is-valid', 'is-invalid'],
- })
- .filter((args: Args) => !(args.labelPosition == 'before' && args.label === longerText))
- .map(args => ({ ...args, id: `a-${crypto.randomUUID()}` }))
- .map(
- (args: Args) =>
- html`
-
- ${meta.render?.({ ...context.args, ...args }, { ...context, id: args.id })}
-
- `,
- );
+ const templateVariants = (bg: string) =>
+ bombArgs({
+ labelPosition: ['before', 'after'],
+ label: ['Notifications', longerText],
+ hiddenLabel: [false],
+ checked: [false, true],
+ disabled: [false, true],
+ validation: ['null', 'is-valid', 'is-invalid'],
+ })
+ .filter((args: Args) => !(args.labelPosition == 'before' && args.label === longerText))
+ .map(args => ({ ...args, id: `${bg}-${crypto.randomUUID()}` }))
+ .map(
+ (args: Args) =>
+ html`
+
+ ${meta.render?.({ ...context.args, ...args }, { ...context, id: args.id })}
+
+ `,
+ );
return html`
${['white', 'dark'].map(
- bg => html`
${templateVariants}
`,
+ bg => html`
${templateVariants(bg)}
`,
)}
`;
diff --git a/packages/documentation/src/stories/components/forms/textarea/textarea.snapshot.stories.ts b/packages/documentation/src/stories/components/forms/textarea/textarea.snapshot.stories.ts
index 41e7cea941..6c6e01806f 100644
--- a/packages/documentation/src/stories/components/forms/textarea/textarea.snapshot.stories.ts
+++ b/packages/documentation/src/stories/components/forms/textarea/textarea.snapshot.stories.ts
@@ -43,7 +43,7 @@ export const Textarea: Story = {
Sizes
${getCombinations('size', context.argTypes.size.options, combinations).map(
(args: Args) => {
- context.id = `a-${crypto.randomUUID()}`;
+ context.id = `${bg}-${crypto.randomUUID()}`;
return html`
${args.title !== undefined && args.title
@@ -62,7 +62,7 @@ export const Textarea: Story = {
)}
Floating Label
${getCombinations('floatingLabel', [true], combinations).map((args: Args) => {
- context.id = `a-${crypto.randomUUID()}`;
+ context.id = `${bg}-${crypto.randomUUID()}`;
return html`
${meta.render?.({ ...context.args, ...args }, context)}
`;
})}
diff --git a/packages/documentation/src/stories/components/forms/textarea/textarea.stories.ts b/packages/documentation/src/stories/components/forms/textarea/textarea.stories.ts
index d3d1d02f35..8f5ac6ceee 100644
--- a/packages/documentation/src/stories/components/forms/textarea/textarea.stories.ts
+++ b/packages/documentation/src/stories/components/forms/textarea/textarea.stories.ts
@@ -154,7 +154,8 @@ export default meta;
type Story = StoryObj;
function renderTextarea(args: Args, context: StoryContext) {
- const id = `${context.viewMode}_${context.story.replace(/\s/g, '-')}_ExampleTextarea`;
+ const id =
+ context.id ?? `${context.viewMode}_${context.story.replace(/\s/g, '-')}_ExampleTextarea`;
const classes = mapClasses({
'form-control': true,
[args.size]: args.size && args.size !== 'null',
diff --git a/packages/styles/src/components/form-range.scss b/packages/styles/src/components/form-range.scss
index 0f0d21b90a..66f698fdf2 100644
--- a/packages/styles/src/components/form-range.scss
+++ b/packages/styles/src/components/form-range.scss
@@ -10,11 +10,24 @@
@use './../variables/components/forms';
@use './../mixins/utilities';
+$track-height: 4px;
+$webkit-progress-height-adjustment: 2px;
+$webkit-thumb-width: 32px;
+
+:has(> .form-range) {
+ @include utilities.focus-style();
+}
+
+@supports not selector(:has(> .form-range)) {
+ .form-range {
+ @include utilities.focus-style();
+ }
+}
+
.form-range {
- // https://codepen.io/thebabydino/pen/goYYrN
- --post-range: calc(var(--post-max) - var(--post-min));
- --post-ratio: calc((var(--post-val) - var(--post-min)) / var(--post-range));
- --post-sx: calc(0.5 * 1.5em + var(--post-ratio) * (100% - 1.5em));
+ &::-webkit-slider-container {
+ overflow-x: clip;
+ }
&::-moz-range-thumb {
border-radius: 50%;
@@ -22,26 +35,75 @@
cursor: pointer;
}
+ &::-webkit-slider-runnable-track {
+ height: $track-height;
+ }
+
+ &::-webkit-slider-thumb {
+ // Source: https://antvil.github.io/css-sos/sos/progress/
+ clip-path: polygon(
+ 0 calc(50% - $track-height * 0.5),
+ 1px calc(50% - #{$track-height * 0.5 + 4px}),
+ 1px 0,
+ $webkit-thumb-width 0,
+ $webkit-thumb-width $webkit-thumb-width,
+ 1px $webkit-thumb-width,
+ 1px calc(50% + #{$track-height * 0.5 + 4px}),
+ 0 calc(50% + #{$track-height * 0.5}),
+ -100vw calc(50% + #{$track-height * 0.5}),
+ -100vw calc(50% - #{$track-height * 0.5})
+ );
+ }
+
+ &::-moz-range-track,
+ &::-moz-range-progress {
+ height: $track-height;
+ }
+
&:not(:disabled, .disabled) {
&::-webkit-slider-runnable-track {
- background: linear-gradient(color.$black, color.$black) 0 / var(--post-sx) 100%;
- background-repeat: no-repeat;
background-color: color.$gray-20;
}
&::-moz-range-progress {
background-color: color.$black;
}
+
+ &::-webkit-slider-thumb {
+ box-shadow: calc(-100vw - $webkit-thumb-width) 0 0 100vw color.$black;
+ }
+
+ &:hover {
+ &::-webkit-slider-thumb {
+ border-width: 3px;
+ }
+
+ &::-moz-range-thumb {
+ border-width: 3px;
+ }
+ }
+
+ @include utilities.focus-style-custom('::-moz-range-thumb') {
+ box-shadow: none; // Remove default style
+ outline: none;
+ }
}
&:disabled,
&.disabled {
&::-webkit-slider-thumb {
border-color: forms.$form-range-thumb-disabled-border-color;
+ border-style: dashed;
+ box-shadow: calc(-100vw - $webkit-thumb-width) 0 0 100vw color.$gray-40;
}
&::-moz-range-thumb {
border-color: forms.$form-range-thumb-disabled-border-color;
+ border-style: dashed;
+ }
+
+ &::-moz-range-progress {
+ background-color: color.$gray-40;
}
}
@@ -57,10 +119,16 @@
// so, the "forced-color-adjust" property is necessary for "linear-gradient" to continue to work
forced-color-adjust: none;
+ &::-webkit-slider-thumb {
+ box-shadow: calc(-100vw - $webkit-thumb-width) 0 0 100vw SelectedItem !important;
+ }
+
+ &::-moz-range-progress {
+ background-color: SelectedItem !important;
+ }
+
&:not(:disabled, .disabled) {
&::-webkit-slider-runnable-track {
- background: linear-gradient(Highlight, Highlight) 0 / var(--post-sx) 100%;
- background-repeat: no-repeat;
background-color: ButtonBorder;
}
@@ -73,38 +141,22 @@
background-color: ButtonText;
}
- &::-moz-range-progress {
- background-color: Highlight;
- }
-
&::-moz-range-thumb {
background-color: ButtonFace;
border-color: ButtonText;
}
-
- &:focus-visible {
- &::-webkit-slider-thumb {
- outline-offset: commons.$border-thick;
- outline: commons.$border-thick solid Highlight;
- }
-
- &::-moz-range-thumb {
- outline-offset: commons.$border-thick;
- outline: commons.$border-thick solid Highlight;
- }
- }
}
&:disabled,
&.disabled {
&::-webkit-slider-thumb {
background-color: ButtonFace;
- border-color: ButtonBorder;
+ border-color: GrayText;
}
&::-moz-range-thumb {
background-color: ButtonFace;
- border-color: ButtonBorder;
+ border-color: GrayText;
}
}
}
diff --git a/packages/styles/src/mixins/_utilities.scss b/packages/styles/src/mixins/_utilities.scss
index 58fd54bb27..63d4363bc3 100644
--- a/packages/styles/src/mixins/_utilities.scss
+++ b/packages/styles/src/mixins/_utilities.scss
@@ -87,11 +87,16 @@
outline: none;
}
-@mixin focus-style($border-radius: commons.$border-radius, $vendor-prefix: '') {
- &:is(:focus-visible, :focus-within, .pretend-focus)#{$vendor-prefix} {
- outline-offset: spacing.$size-line;
- outline: spacing.$size-line solid var(--post-focus-color);
- border-radius: $border-radius;
+@mixin focus-style($vendor-prefix: '') {
+ outline-style: none;
+ outline-offset: spacing.$size-line;
+ outline-width: spacing.$size-line;
+ outline-color: var(--post-focus-color);
+
+ // :has(:focus-visible) mimic a focus-visible-within pseudo-class
+ &:is(:focus-visible, :has(:focus-visible), .pretend-focus)#{$vendor-prefix} {
+ outline-style: solid;
+ border-radius: commons.$border-radius !important;
@include high-contrast-mode() {
outline-color: Highlight;
@@ -100,10 +105,33 @@
// In case rules need to be slightly adjusted
@content;
}
+
+ // When a browser doesn't support :has, use focus-within as a fallback. This means that focus state is displayed on focus and not on focus-visible only (except some browsers like Safari).
+ @supports not selector(:has(:focus-visible)) {
+ &:is(:focus-visible, :focus-within, .pretend-focus)#{$vendor-prefix} {
+ outline-style: solid;
+ border-radius: commons.$border-radius !important;
+
+ @include high-contrast-mode() {
+ outline-color: Highlight;
+ }
+
+ // In case rules need to be slightly adjusted
+ @content;
+ }
+ }
}
@mixin focus-style-custom($vendor-prefix: '') {
- &:is(:focus-visible, :focus-within, .pretend-focus)#{$vendor-prefix} {
+ // :has(:focus-visible) mimic a focus-visible-within pseudo-class
+ &:is(:focus-visible, :has(:focus-visible), .pretend-focus)#{$vendor-prefix} {
@content;
}
+
+ // When a browser doesn't support :has, use focus-within as a fallback. This means that focus state is displayed on focus and not on focus-visible only (except some browsers like Safari).
+ @supports not selector(:has(:focus-visible)) {
+ &:is(:focus-visible, :focus-within, .pretend-focus)#{$vendor-prefix} {
+ @content;
+ }
+ }
}