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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- Modernized `dcc.Tabs`
- Modernized `dcc.DatePickerSingle` and `dcc.DatePickerRange`
- DatePicker calendars can now accept translations as an external script, either with Dash's `external_scripts` or from the assets folder. See [documentation](https://date-fns.org/v4.1.0/docs/CDN) for the underlying library that supports this.
- New `dcc.Button` component that mirrors `html.Button` but with default styles applied

## Changed
- `dcc.Tab` now accepts a `width` prop which can be a pixel or percentage width for an individual tab.
Expand Down
48 changes: 48 additions & 0 deletions components/dash-core-components/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import {ButtonProps} from '../types';
import './css/button.css';

/**
* Similar to dash.html.Button, but with theming and styles applied.
*/
const Button = ({
setProps,
n_blur = 0,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
n_blur_timestamp = -1,
n_clicks = 0,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
n_clicks_timestamp = -1,
type = 'button',
className,
children,
...props
}: ButtonProps) => {
const ctx = window.dash_component_api.useDashContext();
const isLoading = ctx.useLoading();

return (
<button
data-dash-is-loading={isLoading || undefined}
className={'dash-button ' + (className ?? '')}
onBlur={() => {
setProps({
n_blur: n_blur + 1,
n_blur_timestamp: Date.now(),
});
}}
onClick={() => {
setProps({
n_clicks: n_clicks + 1,
n_clicks_timestamp: Date.now(),
});
}}
type={type}
{...props}
>
{children}
</button>
);
};

export default Button;
55 changes: 55 additions & 0 deletions components/dash-core-components/src/components/css/button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.dash-button {
line-height: 32px;
background: color-mix(
in srgb,
var(--Dash-Fill-Interactive-Strong) 5%,
transparent
);
color: var(--Dash-Fill-Interactive-Strong);
padding: 0 calc(var(--Dash-Spacing) * 2);
border-radius: 4px;
border: 1px solid var(--Dash-Fill-Interactive-Strong);
box-sizing: border-box;
vertical-align: middle;
}

/* Hover state - stronger background */
.dash-button:hover {
cursor: pointer;
background: var(--Dash-Fill-Inverse-Strong);
color: var(--Dash-Fill-Interactive-Strong);
}

/* Active state (clicking) - inverted colors */
.dash-button:active {
background: var(--Dash-Fill-Interactive-Strong);
color: var(--Dash-Fill-Inverse-Strong);
}

/* Keyboard focus - inverted colors */
.dash-button:focus-visible {
outline: none;
background: var(--Dash-Fill-Interactive-Strong);
color: var(--Dash-Fill-Inverse-Strong);
}

/* Hover after keyboard focus - keep inverted but acknowledge hover */
.dash-button:focus-visible:hover {
background: var(--Dash-Fill-Interactive-Strong);
color: var(--Dash-Fill-Inverse-Strong);
}

/* Active state after keyboard focus - inverted colors */
.dash-button:focus-visible:active {
background: var(--Dash-Fill-Interactive-Strong);
color: var(--Dash-Fill-Inverse-Strong);
}

/* Disabled state */
.dash-button:disabled {
opacity: 0.6;
cursor: not-allowed;
background: var(--Dash-Fill-Disabled);
color: var(--Dash-Text-Strong);
border-color: var(--Dash-Stroke-Weak);
}
2 changes: 2 additions & 0 deletions components/dash-core-components/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable import/prefer-default-export */
import Button from './components/Button';
import Checklist from './components/Checklist';
import Clipboard from './components/Clipboard.react';
import ConfirmDialog from './components/ConfirmDialog.react';
Expand Down Expand Up @@ -28,6 +29,7 @@ import Upload from './components/Upload.react';
import './components/css/dcc.css';

export {
Button,
Checklist,
Clipboard,
ConfirmDialog,
Expand Down
113 changes: 112 additions & 1 deletion components/dash-core-components/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {ButtonHTMLAttributes, DetailedHTMLProps} from 'react';
import {BaseDashProps, DashComponent} from '@dash-renderer/types';

export enum PersistenceTypes {
Expand Down Expand Up @@ -52,6 +52,117 @@ export interface BaseDccProps<T>
persistence_type?: PersistenceTypes;
}

export type ButtonProps = BaseDccProps<ButtonProps> & {
/**
* The children of this component.
*/
children?: React.ReactNode;
/**
* Defines the type of the element.
*/
type?: 'submit' | 'reset' | 'button';
/**
* The element should be automatically focused after the page loaded.
*/
autoFocus?: boolean;
/**
* Indicates whether the user can interact with the element.
*/
disabled?: boolean;
/**
* Indicates the form that is the owner of the element.
*/
form?: string;
/**
* Indicates the action of the element, overriding the action defined in the <form>.
*/
formAction?: string;
/**
* If the button/input is a submit button (type="submit"), this attribute sets the encoding type to use during form submission. If this attribute is specified, it overrides the enctype attribute of the button's form owner.
*/
formEncType?: string;
/**
* If the button/input is a submit button (type="submit"), this attribute sets the submission method to use during form submission (GET, POST, etc.). If this attribute is specified, it overrides the method attribute of the button's form owner.
*/
formMethod?: string;
/**
* If the button/input is a submit button (type="submit"), this boolean attribute specifies that the form is not to be validated when it is submitted. If this attribute is specified, it overrides the novalidate attribute of the button's form owner.
*/
formNoValidate?: boolean;
/**
* If the button/input is a submit button (type="submit"), this attribute specifies the browsing context (for example, tab, window, or inline frame) in which to display the response that is received after submitting the form. If this attribute is specified, it overrides the target attribute of the button's form owner.
*/
formTarget?: string;
/**
* Name of the element. For example used by the server to identify the fields in form submits.
*/
name?: string;
/**
* Defines a default value which will be displayed in the element on page load.
*/
value?: string | string[] | number;
/**
* Keyboard shortcut to activate or add focus to the element.
*/
accessKey?: string;
/**
* Indicates whether the element's content is editable.
*/
contentEditable?: boolean | 'true' | 'false' | 'inherit';
/**
* Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left).
*/
dir?: string;
/**
* Defines whether the element can be dragged.
*/
draggable?: boolean;
/**
* Prevents rendering of given element, while keeping child elements, e.g. script elements, active.
*/
hidden?: boolean;
/**
* Defines the language used in the element.
*/
lang?: string;
/**
* Defines the role of an element in the context of accessibility.
*/
role?: string;
/**
* Indicates whether spell checking is allowed for the element.
*/
spellCheck?: boolean;
/**
* Defines CSS styles which will override styles previously set.
*/
style?: React.CSSProperties;
/**
* Overrides the browser's default tab order and follows the one specified instead.
*/
tabIndex?: number;
/**
* Text to be displayed in a tooltip when hovering over the element.
*/
title?: string;
/**
* Number of times the button lost focus.
*/
n_blur?: number;
/**
* Last time the button lost focus.
*/
n_blur_timestamp?: number;
/**
* Number of times the button has been clicked.
*/
n_clicks?: number;
/**
* Last time the button was clicked.
*/
n_clicks_timestamp?: number;
};

export enum HTMLInputTypes {
// Only allowing the input types with wide browser compatibility
'text' = 'text',
Expand Down
Loading
Loading