Skip to content
Closed
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
4 changes: 4 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ ion-checkbox,prop,justify,"end" | "space-between" | "start",'space-between',fals
ion-checkbox,prop,labelPlacement,"end" | "fixed" | "stacked" | "start",'start',false,false
ion-checkbox,prop,mode,"ios" | "md",undefined,false,false
ion-checkbox,prop,name,string,this.inputId,false,false
ion-checkbox,prop,required,boolean,false,false,false
ion-checkbox,prop,shape,"rectangular" | "soft" | undefined,'soft',false,true
ion-checkbox,prop,size,"default" | "small" | undefined,'default',false,true
ion-checkbox,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-checkbox,prop,value,any,'on',false,false
ion-checkbox,event,ionBlur,void,true
Expand All @@ -338,6 +341,7 @@ ion-checkbox,css-prop,--checkmark-width
ion-checkbox,css-prop,--size
ion-checkbox,css-prop,--transition
ion-checkbox,part,container
ion-checkbox,part,focus-ring
ion-checkbox,part,label
ion-checkbox,part,mark

Expand Down
24 changes: 24 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,18 @@ export namespace Components {
* The name of the control, which is submitted with the form data.
*/
"name": string;
/**
* If `true`, the checkbox will be presented with an error style when it is unchecked.
*/
"required": boolean;
/**
* Set to `"soft"` for a checkbox with more rounded corners.
*/
"shape"?: 'soft' | 'rectangular';
/**
* Set to `"small"` for a checkbox with less height and padding or to `"default"` for a checkbox with the default height and padding.
*/
"size"?: 'small' | 'default';
/**
* The theme determines the visual appearance of the component.
*/
Expand Down Expand Up @@ -5952,6 +5964,18 @@ declare namespace LocalJSX {
* Emitted when the checkbox has focus.
*/
"onIonFocus"?: (event: IonCheckboxCustomEvent<void>) => void;
/**
* If `true`, the checkbox will be presented with an error style when it is unchecked.
*/
"required"?: boolean;
/**
* Set to `"soft"` for a checkbox with more rounded corners.
*/
"shape"?: 'soft' | 'rectangular';
/**
* Set to `"small"` for a checkbox with less height and padding or to `"default"` for a checkbox with the default height and padding.
*/
"size"?: 'small' | 'default';
/**
* The theme determines the visual appearance of the component.
*/
Expand Down
165 changes: 165 additions & 0 deletions core/src/components/checkbox/checkbox.ionic.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
@import "./checkbox";
@import "./checkbox.ionic.vars";

// ionic Checkbox
// --------------------------------------------------

:host {
// Border
--border-radius: calc(var(--size) * .125);
--border-width: #{$checkbox-ionic-icon-border-width};
--border-style: #{$checkbox-ionic-icon-border-style};
--border-color: #{$checkbox-ionic-icon-border-color-off};
--checkmark-width: 3;
--padding-top: #{$checkbox-ionic-padding-top};
--padding-bottom: #{$checkbox-ionic-padding-bottom};

// Background
--checkbox-background: #{$checkbox-ionic-icon-background-color-off};

// Transition
--transition: #{background $checkbox-ionic-transition-duration $checkbox-ionic-transition-easing};

// Size
--size: #{$checkbox-ionic-icon-size};
// add to existing selector

// margin is required to make room for outline on focus, otherwise the outline may get cut off
@include margin($checkbox-ionic-outline-width);
@include padding(--padding-top, null, --padding-bottom, null);

// Target area
&::after {
@include position(50%, 0, null, 0);

position: absolute;

height: 100%;
min-height: 48px;

transform: translateY(-50%);

content: "";

cursor: pointer;

z-index: 1;
}

.native-wrapper{
position: relative;
}
}

// Ionic Design Checkbox Sizes
// --------------------------------------------------
:host(.checkbox-small) {
--padding-top: #{$checkbox-ionic-small-padding-top};
--padding-bottom: #{$checkbox-ionic-small-padding-bottom};

// Size
--size: #{$checkbox-ionic-small-icon-size};
}

// Ionic Design Checkbox Shapes
// --------------------------------------------------
:host(.checkbox-rectangular) {
--border-radius: #{$checkbox-ionic-rectangular-border};
}

// Ionic Design Checkbox Disabled
// --------------------------------------------------
// disabled, indeterminate checkbox
:host(.checkbox-disabled.checkbox-indeterminate) .checkbox-icon {
border-width: 0;

background-color: #74aafc;
}

// disabled, unchecked checkbox
:host(.checkbox-disabled) .checkbox-icon {
border-color: #c9c9c9;

background-color: #f5f5f5;
}
// disabled, checked checkbox
:host(.checkbox-disabled.checkbox-checked) .checkbox-icon {
border-width: 0;

background-color: #A8C8F8;
}

// Ionic Design Checkbox Required State
// --------------------------------------------------
// Unhecked checkbox with `required` property set to true
:host(.checkbox-required:not(.checkbox-checked):not(.checkbox-indeterminate)) {
.checkbox-icon {
border-color: #f72c2c;
}
}

// Focused: Unchecked checkbox with `required` property set to true
:host(.ion-focusable.checkbox-required:not(.checkbox-checked):not(.checkbox-indeterminate)) .checkbox-icon {
outline-color: #ffafaf;
}

// Ionic Design Checkbox Focus Ring
// --------------------------------------------------
:host(.ion-focused:not(.checkbox-disabled)) .focus-ring {
@include position(-4px, -4px, -4px, -4px);
position: absolute;

width: calc(100% + 8px);
height: calc(100% + 8px);

transition: border-color 0.3s;

border: 2px solid $checkbox-ionic-focus-ring-color;

@include border-radius(var(--border-radius));

content: "";
box-sizing: border-box;
}

// Required state
:host(.ion-focused.checkbox-required) .focus-ring {
border-color:$checkbox-ionic-focus-required-ring-color;
}

// Checkbox: Hover
// --------------------------------------------------------
@media (any-hover: hover) {
:host(:hover) .checkbox-icon {
background-color: #ececec; // mix of 'white', '#121212', 0.08, 'rgb'
}

:host(:hover.checkbox-checked) .checkbox-icon,
:host(:hover.checkbox-indeterminate) .checkbox-icon {
background-color: #1061da; // mix of '#1068eb', '#121212', 0.08, 'rgb'
}

// unchecked checkbox with `required` property set to true
:host(:hover.checkbox-required:not(.checkbox-checked):not(.checkbox-indeterminate)) {
.checkbox-icon {
border-color: #ee2b2b;
}
}
}

// Checkbox: Active
// --------------------------------------------------------
:host(.ion-activated) .checkbox-icon {
background-color: #e3e3e3; // mix of 'white', '#121212', 0.12, 'rgb'
}

:host(.ion-activated.checkbox-checked) .checkbox-icon,
:host(.ion-activated.checkbox-indeterminate) .checkbox-icon {
background-color: #105ed1; // mix of '#1068eb', '#121212', 0.12, 'rgb'
}

:host(.checkbox-label-placement-start) {
display: flex;

justify-content: space-between;
}
63 changes: 63 additions & 0 deletions core/src/components/checkbox/checkbox.ionic.vars.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@import "../../themes/ionic.globals.md";
@import "../item/item.md.vars";

// ionic Checkbox
// --------------------------------------------------

/// @prop - Background color of the checkbox icon when off
$checkbox-ionic-icon-background-color-off: $item-md-background !default;

/// @prop - Size of the checkbox icon
/// The icon size does not use dynamic font
/// because it does not scale in native.
$checkbox-ionic-icon-size: 24px !default;

/// @prop - Icon size of the checkbox for the small size
$checkbox-ionic-small-icon-size: 16px !default;

/// @prop - Border width of the checkbox icon
$checkbox-ionic-icon-border-width: 1px !default;

/// @prop - Border style of the checkbox icon
$checkbox-ionic-icon-border-style: solid !default;

/// @prop - Border color of the checkbox icon when off
$checkbox-ionic-icon-border-color-off: #9a9a9a !default;

/// @prop - Outline width of the checkbox
$checkbox-ionic-outline-width: 2px !default;

/// @prop - Padding top of the checkbox for the default size
$checkbox-ionic-padding-top: 12px !default;

/// @prop - Padding bottom of the button for the default size
$checkbox-ionic-padding-bottom: 12px !default;

/// @prop - Padding top of the checkbox for the small size
$checkbox-ionic-small-padding-top: 16px !default;

/// @prop - Padding bottom of the button for the small size
$checkbox-ionic-small-padding-bottom: 16px !default;

/// @prop - Focus color of the checkbox
$checkbox-ionic-focus-ring-color: #9ec4fd !default;

/// @prop - Focus color of the required checkbox
$checkbox-ionic-focus-required-ring-color: #FFAFAF !default;

/// @prop - Transition duration of the checkbox
$checkbox-ionic-transition-duration: 180ms !default;

/// @prop - Transition easing of the checkbox
$checkbox-ionic-transition-easing: cubic-bezier(.4, 0, .2, 1) !default;


// Checkbox Shapes
// -------------------------------------------------------------------------------

/* Rectangular */
/// @prop - Rectangular border radius of the checkbox
$checkbox-ionic-rectangular-border: 0 !default;



32 changes: 31 additions & 1 deletion core/src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ import type { CheckboxChangeEventDetail } from './checkbox-interface';
* @part container - The container for the checkbox mark.
* @part label - The label text describing the checkbox.
* @part mark - The checkmark used to indicate the checked state.
* @part focus-ring - The visual indicator that appears as an outline around the checkbox when focused. Only available for the Ionic theme.
*/
@Component({
tag: 'ion-checkbox',
styleUrls: {
ios: 'checkbox.ios.scss',
md: 'checkbox.md.scss',
ionic: 'checkbox.md.scss',
ionic: 'checkbox.ionic.scss',
},
shadow: true,
})
Expand Down Expand Up @@ -98,6 +99,22 @@ export class Checkbox implements ComponentInterface {
*/
@Prop() alignment: 'start' | 'center' = 'center';

/**
* If `true`, the checkbox will be presented with an error style when it is unchecked.
*/
@Prop() required = false;

/**
* Set to `"soft"` for a checkbox with more rounded corners.
*/
@Prop() shape?: 'soft' | 'rectangular' = 'soft';

/**
* Set to `"small"` for a checkbox with less height and padding or to `"default"`
* for a checkbox with the default height and padding.
*/
@Prop() size?: 'small' | 'default' = 'default';

/**
* Emitted when the checked property has changed
* as a result of a user action such as a click.
Expand Down Expand Up @@ -181,6 +198,9 @@ export class Checkbox implements ComponentInterface {
name,
value,
alignment,
required,
size,
shape,
} = this;
const theme = getIonTheme(this);

Expand All @@ -201,6 +221,9 @@ export class Checkbox implements ComponentInterface {
[`checkbox-justify-${justify}`]: true,
[`checkbox-alignment-${alignment}`]: true,
[`checkbox-label-placement-${labelPlacement}`]: true,
'checkbox-required': required,
[`checkbox-${size}`]: true,
[`checkbox-${shape}`]: true,
})}
onClick={this.onClick}
>
Expand Down Expand Up @@ -233,6 +256,7 @@ export class Checkbox implements ComponentInterface {
<svg class="checkbox-icon" viewBox="0 0 24 24" part="container">
{path}
</svg>
{theme === 'ionic' && <div part="focus-ring" class="focus-ring"></div>}
Copy link
Contributor

Choose a reason for hiding this comment

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

Be sure to document this shadow part at the top of the file. You can checkout what was done for button on the latest next branch. We should make it clear this shadow part is only available in the ionic theme.

</div>
</label>
</Host>
Expand All @@ -252,6 +276,12 @@ export class Checkbox implements ComponentInterface {
) : (
<path d="M1.73,12.91 8.1,19.28 22.79,4.59" part="mark" />
);
} else if (theme === 'ionic') {
path = indeterminate ? (
<path d="M6.5 12H17.5" stroke-linecap="round" part="mark" />
) : (
<path d="M6 12.5L10 16.5L18.5 8" stroke-linecap="round" stroke-linejoin="round" part="mark" />
);
}

return path;
Expand Down
Loading