Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
7 changes: 7 additions & 0 deletions change/@ni-ok-react-7f04b43d-439e-4848-b394-511e0909be4d.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Comment thread
atmgrifter00 marked this conversation as resolved.
"type": "minor",
"comment": "Add React wrapper for the basic slider",
"packageName": "@ni/ok-react",
"email": "198982749+Copilot@users.noreply.github.com",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions packages/ok-components/src/all-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import '@ni/spright-components/dist/esm/all-components';

import './basic/all-basic';
import './fv/all-fv';
import './ex/all-ex';
import './ts/all-ts';
1 change: 1 addition & 0 deletions packages/ok-components/src/basic/all-basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './slider';
28 changes: 28 additions & 0 deletions packages/ok-components/src/basic/slider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
DesignSystem,
Slider as FoundationSlider,
sliderTemplate as template,
type SliderOptions
} from '@ni/fast-foundation';
import { styles } from './styles';

declare global {
interface HTMLElementTagNameMap {
'ok-basic-slider': Slider;
}
}

/**
* A Nimble-styled slider control.
*/
export class Slider extends FoundationSlider {}

const okBasicSlider = Slider.compose<SliderOptions>({
baseName: 'basic-slider',
baseClass: FoundationSlider,
template,
styles
});

DesignSystem.getOrCreate().withPrefix('ok').register(okBasicSlider());
export const sliderTag = 'ok-basic-slider';
158 changes: 158 additions & 0 deletions packages/ok-components/src/basic/slider/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { css } from '@ni/fast-element';
import {
applicationBackgroundColor,
bodyDisabledFontColor,
bodyFont,
bodyFontColor,
borderColor,
borderHoverColor,
borderRgbPartialColor,
borderWidth,
fillDownColor,
fillSelectedColor,
smallDelay
} from '@ni/nimble-components/dist/esm/theme-provider/design-tokens';
import { display } from '../../utilities/style/display';

export const styles = css`
@layer base, hover, focusVisible, active, disabled, top;

@layer base {
${display('inline-block')}

:host {
width: 240px;
height: 32px;
outline: none;
color: ${bodyFontColor};
font: ${bodyFont};
cursor: pointer;
touch-action: none;
}

:host([orientation='vertical']) {
width: 32px;
height: 240px;
}

:host([readonly]) {
cursor: default;
}

.positioning-region {
position: relative;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
}

.track {
position: relative;
width: 100%;
height: 4px;
border-radius: 2px;
background-color: rgba(${borderRgbPartialColor}, 0.3);
}

.track-start {
position: absolute;
inset-block: 0;
left: 0;
border-radius: inherit;
background-color: ${fillSelectedColor};
}

.thumb-container {
position: absolute;
top: 50%;
width: 16px;
height: 16px;
box-sizing: border-box;
border: ${borderWidth} solid ${borderColor};
border-radius: 50%;
background-color: ${applicationBackgroundColor};
transform: translate(50%, -50%);
transition:
border-color ${smallDelay} ease-in-out,
box-shadow ${smallDelay} ease-in-out,
background-color ${smallDelay} ease-in-out;
}

:host([orientation='vertical']) .positioning-region {
align-items: initial;
}

:host([orientation='vertical']) .track {
width: 4px;
height: 100%;
}

:host([orientation='vertical']) .track-start {
inset-block-start: 0;
inset-inline: 0;
}

:host([orientation='vertical']) .thumb-container {
top: auto;
left: 50%;
transform: translate(-50%, 50%);
}

::slotted(*) {
color: ${bodyFontColor};
font: ${bodyFont};
}
}

@layer hover {
:host(:not([disabled]):not([readonly]):hover) .thumb-container {
border-color: ${borderHoverColor};
box-shadow: 0 0 0 ${borderWidth} ${borderHoverColor};
}
}

@layer focusVisible {
:host(:focus-visible) .thumb-container {
border-color: ${borderHoverColor};
box-shadow:
0 0 0 ${borderWidth} ${applicationBackgroundColor},
0 0 0 calc(${borderWidth} * 2) ${borderHoverColor};
}
}

@layer active {
:host(:not([disabled]):not([readonly]):active) .thumb-container {
border-color: ${borderHoverColor};
background-color: ${fillDownColor};
}
}

@layer disabled {
:host([disabled]) {
color: ${bodyDisabledFontColor};
cursor: default;
}

:host([disabled]) .track {
background-color: rgba(${borderRgbPartialColor}, 0.1);
}

:host([disabled]) .track-start {
background-color: rgba(${borderRgbPartialColor}, 0.2);
}

:host([disabled]) .thumb-container {
border-color: rgba(${borderRgbPartialColor}, 0.2);
background-color: ${applicationBackgroundColor};
box-shadow: none;
}

:host([disabled]) ::slotted(*) {
color: ${bodyDisabledFontColor};
}
}

@layer top {}
`;
22 changes: 22 additions & 0 deletions packages/ok-components/src/basic/slider/tests/slider.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { html } from '@ni/fast-element';
import { Slider, sliderTag } from '..';
import { fixture } from '../../../utilities/tests/fixture';

describe('Slider', () => {
it('can construct an element instance', () => {
expect(document.createElement(sliderTag)).toBeInstanceOf(Slider);
});

it('provides the FAST Foundation slider template', async () => {
const { element, connect, disconnect } = await fixture<Slider>(
html`<${sliderTag}></${sliderTag}>`
);
await connect();

expect(element.shadowRoot?.querySelector('[part="track-container"]')).not.toBeNull();
expect(element.shadowRoot?.querySelector('[part="track-start"]')).not.toBeNull();
expect(element.shadowRoot?.querySelector('[part="thumb-container"]')).not.toBeNull();

await disconnect();
});
});
18 changes: 18 additions & 0 deletions packages/react-workspace/ok-react/src/basic/slider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';

import {
Slider,
sliderTag
} from '@ni/ok-components/dist/esm/basic/slider';
import { wrap, type EventName } from '../../utilities/react-wrapper';

export { sliderTag };
export { type Slider };
export const OkBasicSlider = wrap(Slider, {
events: {
onChange: 'change' as EventName<SliderChangeEvent>
}
});
export interface SliderChangeEvent extends CustomEvent {
target: Slider;
}
60 changes: 60 additions & 0 deletions packages/storybook/src/ok/basic/slider/slider-matrix.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { Meta, StoryFn } from '@storybook/html-vite';
import { html, type ViewTemplate } from '@ni/fast-element';
import { sliderTag } from '@ni/ok-components/dist/esm/basic/slider';
import {
cartesianProduct,
createMatrix,
createMatrixInteractionsFromStates,
createMatrixThemeStory,
sharedMatrixParameters
} from '../../../utilities/matrix';

const metadata: Meta = {
title: 'Tests Ok/Basic Slider',
parameters: {
...sharedMatrixParameters()
}
};

export default metadata;

type SliderState = readonly [string, boolean, boolean];

const states: SliderState[] = [
['Enabled', false, false],
['Readonly', false, true],
['Disabled', true, false]
];

const interactionStates = cartesianProduct([states] as const);

const component = ([name, disabled, readOnly]: SliderState): ViewTemplate => html`
<div style="display: inline-flex; flex-direction: column; gap: 8px; margin: 8px;">
<span>${() => name}</span>
<${sliderTag}
value="40"
?disabled="${() => disabled}"
?readonly="${() => readOnly}"
></${sliderTag}>
</div>
`;

export const statesThemeMatrix: StoryFn = createMatrixThemeStory(
createMatrix(component, [states])
);

export const orientationsThemeMatrix: StoryFn = createMatrixThemeStory(html`
<div style="display: flex; gap: 32px; align-items: flex-start; padding: 16px;">
<${sliderTag} value="40"></${sliderTag}>
<${sliderTag} value="40" orientation="vertical"></${sliderTag}>
</div>
`);

export const interactionsThemeMatrix: StoryFn = createMatrixThemeStory(
createMatrixInteractionsFromStates(component, {
hover: interactionStates,
hoverActive: interactionStates,
active: interactionStates,
focus: interactionStates
})
);
16 changes: 16 additions & 0 deletions packages/storybook/src/ok/basic/slider/slider.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Canvas, Controls, Meta, Title } from '@storybook/addon-docs/blocks';
import ComponentApisLink from '../../../docs/component-apis-link.mdx';
import * as sliderStories from './slider.stories';

<Meta of={sliderStories} />
<Title of={sliderStories} />

A Nimble-styled slider based on the FAST Foundation slider.

<Canvas of={sliderStories.slider} />

## API

<Controls of={sliderStories.slider} />

<ComponentApisLink />
Loading
Loading