Parcourir la source

Fix Lynx rendering

Properly specify input labels layout on Lynx.
master
TheoryOfNekomata il y a 11 mois
Parent
révision
6f00e7d138
52 fichiers modifiés avec 1152 ajouts et 1090 suppressions
  1. +7
    -2
      TODO.md
  2. +5
    -9
      categories/choice/react/package.json
  3. +0
    -22
      categories/choice/react/scripts/build.ts
  4. +28
    -25
      categories/choice/react/src/components/ComboBox/index.tsx
  5. +0
    -17
      categories/choice/react/src/components/DropdownSelect/DropdownSelect.css
  6. +52
    -26
      categories/choice/react/src/components/DropdownSelect/index.tsx
  7. +0
    -17
      categories/choice/react/src/components/MenuSelect/MenuSelect.css
  8. +52
    -26
      categories/choice/react/src/components/MenuSelect/index.tsx
  9. +0
    -7
      categories/choice/react/src/components/RadioButton/RadioButton.css
  10. +15
    -1
      categories/choice/react/src/components/RadioButton/index.tsx
  11. +0
    -7
      categories/choice/react/src/components/RadioTickBox/RadioTickBox.css
  12. +15
    -1
      categories/choice/react/src/components/RadioTickBox/index.tsx
  13. +1
    -0
      categories/color/react/.eslintrc
  14. +5
    -6
      categories/color/react/package.json
  15. +0
    -19
      categories/color/react/scripts/build.ts
  16. +0
    -7
      categories/color/react/src/components/ColorPicker/ColorPicker.css
  17. +14
    -0
      categories/color/react/src/components/ColorPicker/index.tsx
  18. +28
    -25
      categories/formatted/react/src/components/EmailInput/index.tsx
  19. +28
    -25
      categories/formatted/react/src/components/PatternTextInput/index.tsx
  20. +28
    -25
      categories/formatted/react/src/components/PhoneNumberInput/index.tsx
  21. +28
    -25
      categories/formatted/react/src/components/UrlInput/index.tsx
  22. +28
    -25
      categories/freeform/react/src/components/MaskedTextInput/index.tsx
  23. +28
    -25
      categories/freeform/react/src/components/MultilineTextInput/index.tsx
  24. +28
    -25
      categories/freeform/react/src/components/TextInput/index.tsx
  25. +5
    -10
      categories/multichoice/react/package.json
  26. +0
    -23
      categories/multichoice/react/scripts/build.ts
  27. +0
    -17
      categories/multichoice/react/src/components/MenuMultiSelect/MenuMultiSelect.css
  28. +52
    -26
      categories/multichoice/react/src/components/MenuMultiSelect/index.tsx
  29. +0
    -109
      categories/multichoice/react/src/components/TagInput/TagInput.css
  30. +146
    -31
      categories/multichoice/react/src/components/TagInput/index.tsx
  31. +0
    -15
      categories/multichoice/react/src/components/ToggleButton/ToggleButton.css
  32. +21
    -1
      categories/multichoice/react/src/components/ToggleButton/index.tsx
  33. +0
    -118
      categories/multichoice/react/src/components/ToggleSwitch/ToggleSwitch.css
  34. +123
    -1
      categories/multichoice/react/src/components/ToggleSwitch/index.tsx
  35. +0
    -15
      categories/multichoice/react/src/components/ToggleTickBox/ToggleTickBox.css
  36. +21
    -1
      categories/multichoice/react/src/components/ToggleTickBox/index.tsx
  37. +5
    -7
      categories/number/react/package.json
  38. +0
    -20
      categories/number/react/scripts/build.ts
  39. +0
    -12
      categories/number/react/src/components/NumberSpinner/NumberSpinner.css
  40. +46
    -27
      categories/number/react/src/components/NumberSpinner/index.tsx
  41. +0
    -157
      categories/number/react/src/components/Slider/Slider.css
  42. +164
    -1
      categories/number/react/src/components/Slider/index.tsx
  43. +28
    -25
      categories/temporal/react/src/components/DateDropdown/index.tsx
  44. +12
    -12
      pnpm-lock.yaml
  45. +28
    -25
      showcases/web-kitchensink-reactnext/src/components/temporal/TimeSpinner/index.tsx
  46. +28
    -25
      showcases/web-kitchensink-reactnext/src/components/temporal/WeekInput/index.tsx
  47. +28
    -25
      showcases/web-kitchensink-reactnext/src/components/temporal/YearMonthInput/index.tsx
  48. +0
    -16
      showcases/web-kitchensink-reactnext/src/pages/_app.tsx
  49. +17
    -0
      showcases/web-kitchensink-reactnext/src/pages/categories/color/index.tsx
  50. +2
    -2
      showcases/web-kitchensink-reactnext/src/pages/categories/option/index.tsx
  51. +1
    -0
      showcases/web-kitchensink-reactnext/src/styles/globals.css
  52. +35
    -2
      showcases/web-kitchensink-reactnext/tailwind.config.js

+ 7
- 2
TODO.md Voir le fichier

@@ -12,7 +12,7 @@
- [X] RadioTickBox
- Color
- [ ] ColorPicker
- [X] Swatch
- [X] Swatch (unify with color picker? Swatch is basically a readonly color picker with click-to-copy behavior)
- Code
- [ ] CodeInput (extract to own package)
- [X] CodeBlock (`react-refractor`)
@@ -24,7 +24,7 @@
- Freeform
- [X] MaskedTextInput
- [X] MultilineTextInput
- [X] TextInput
- [X] TextInput (add click-to-copy prop)
- Geo
- [ ] Map
- Information
@@ -66,4 +66,9 @@

# Others
- [X] Add `select-none` to input labels, etc.
- [ ] Add indicators to components (select, datetime input etc)
- [ ] Test all components!
- [ ] Where to put the "click-to-copy" textboxes? Does `Swatch`
belong to this category?
- [ ] Add `aria-*` attributes to all components
- [ ] react-refractor, fix rendering on Lynx!

+ 5
- 9
categories/choice/react/package.json Voir le fichier

@@ -28,7 +28,6 @@
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"tslib": "^2.5.0",
"tsx": "^3.12.7",
"typescript": "^4.9.5",
"vitest": "^0.33.0"
},
@@ -38,7 +37,7 @@
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build && tsx scripts/build.ts",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
@@ -63,7 +62,8 @@
},
"dependencies": {
"@tesseract-design/web-base": "workspace:*",
"clsx": "^1.2.1"
"clsx": "^1.2.1",
"tailwindcss": "3.3.2"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
@@ -77,13 +77,9 @@
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
},
"./dist/DropdownSelect.css": "./dist/DropdownSelect.css",
"./dist/MenuSelect.css": "./dist/MenuSelect.css",
"./dist/RadioButton.css": "./dist/RadioButton.css",
"./dist/RadioTickBox.css": "./dist/RadioTickBox.css"
}
},
"typesVersions": {
"*": {}
}
}
}

+ 0
- 22
categories/choice/react/scripts/build.ts Voir le fichier

@@ -1,22 +0,0 @@
import { copyFileSync, readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';

const doCopy = (src: string, dest: string) => {
const trueSrc = resolve(src);
const trueDest = resolve(dest);
console.log('Copying...');
console.log(`${trueSrc} -> ${trueDest}`);
copyFileSync(trueSrc, trueDest);
const packageJsonContents = readFileSync('./package.json', 'utf-8');
const packageJson = JSON.parse(packageJsonContents);
packageJson.exports[dest] = dest;
const newPackageJsonContents = JSON.stringify(packageJson, null, 2);
console.log('Updating package.json...');
writeFileSync('./package.json', newPackageJsonContents);
console.log('Done');
}

doCopy('./src/components/DropdownSelect/DropdownSelect.css', './dist/DropdownSelect.css');
doCopy('./src/components/MenuSelect/MenuSelect.css', './dist/MenuSelect.css');
doCopy('./src/components/RadioButton/RadioButton.css', './dist/RadioButton.css');
doCopy('./src/components/RadioTickBox/RadioTickBox.css', './dist/RadioTickBox.css');

+ 28
- 25
categories/choice/react/src/components/ComboBox/index.tsx Voir le fichier

@@ -115,6 +115,34 @@ export const ComboBox = React.forwardRef<ComboBoxDerivedElement, ComboBoxProps>(
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -156,31 +184,6 @@ export const ComboBox = React.forwardRef<ComboBoxDerivedElement, ComboBoxProps>(
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 17
categories/choice/react/src/components/DropdownSelect/DropdownSelect.css Voir le fichier

@@ -1,17 +0,0 @@
.tesseract-design-dropdown-select optgroup {
color: rgb(var(--color-positive) / 50%);
text-transform: uppercase;
font-size: 0.75em;
margin-top: 0.5rem;
user-select: none;
}

.tesseract-design-dropdown-select optgroup > option {
color: rgb(var(--color-positive));
text-transform: none;
font-size: 1.333333em;
}

.tesseract-design-dropdown-select option {
user-select: none;
}

+ 52
- 26
categories/choice/react/src/components/DropdownSelect/index.tsx Voir le fichier

@@ -1,5 +1,6 @@
import * as React from 'react';
import { TextControl } from '@tesseract-design/web-base';
import plugin from 'tailwindcss/plugin';
import clsx from 'clsx';

/**
@@ -45,6 +46,28 @@ export interface DropdownSelectProps extends Omit<React.HTMLProps<DropdownSelect
hiddenLabel?: boolean,
}

export const dropdownSelectPlugin = plugin(({ addComponents }) => {
addComponents({
'.dropdown-select': {
'& optgroup': {
'color': 'rgb(var(--color-positive) / 50%)',
'text-transform': 'uppercase',
'font-size': '0.75em',
'margin-top': '0.5rem',
'user-select': 'none',
},
'& optgroup > option': {
'color': 'rgb(var(--color-positive))',
'text-transform': 'none',
'font-size': '1.333333em',
},
'& option': {
'user-select': 'none',
},
},
});
});

/**
* Component for selecting a single value from a dropdown.
*/
@@ -84,6 +107,34 @@ export const DropdownSelect = React.forwardRef<DropdownSelectDerivedElement, Dro
data-testid="base"
style={style}
>
{label && (
<>
<label
htmlFor={id}
data-testid="label"
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<select
{...etcProps}
ref={forwardedRef}
@@ -92,7 +143,7 @@ export const DropdownSelect = React.forwardRef<DropdownSelectDerivedElement, Dro
data-testid="input"
role="combobox"
className={clsx(
'tesseract-design-dropdown-select bg-negative rounded-inherit w-full peer block appearance-none cursor-pointer select-none font-inherit',
'dropdown-select bg-negative rounded-inherit w-full peer block appearance-none cursor-pointer select-none font-inherit',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
@@ -124,31 +175,6 @@ export const DropdownSelect = React.forwardRef<DropdownSelectDerivedElement, Dro
>
{children}
</select>
{label && (
<label
htmlFor={id}
data-testid="label"
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 17
categories/choice/react/src/components/MenuSelect/MenuSelect.css Voir le fichier

@@ -1,17 +0,0 @@
.tesseract-design-menu-select optgroup {
color: rgb(var(--color-positive) / 50%);
text-transform: uppercase;
font-size: 0.75em;
margin-top: 0.5rem;
user-select: none;
}

.tesseract-design-menu-select optgroup > option {
color: rgb(var(--color-positive));
text-transform: none;
font-size: 1.333333em;
}

.tesseract-design-menu-select option {
user-select: none;
}

+ 52
- 26
categories/choice/react/src/components/MenuSelect/index.tsx Voir le fichier

@@ -1,6 +1,7 @@
import * as React from 'react';
import { TextControl } from '@tesseract-design/web-base';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

/**
* Derived HTML element of the {@link MenuSelect} component.
@@ -49,6 +50,28 @@ export interface MenuSelectProps extends Omit<React.HTMLProps<MenuSelectDerivedE
startingHeight?: number | string,
}

export const menuSelectPlugin = plugin(({ addComponents }) => {
addComponents({
'.menu-select': {
'& optgroup': {
'color': 'rgb(var(--color-positive) / 50%)',
'text-transform': 'uppercase',
'font-size': '0.75em',
'margin-top': '0.5rem',
'user-select': 'none',
},
'& optgroup > option': {
'color': 'rgb(var(--color-positive))',
'text-transform': 'none',
'font-size': '1.333333em',
},
'& option': {
'user-select': 'none',
},
},
});
});

/**
* Component for selecting a single value from a menu.
*/
@@ -86,6 +109,34 @@ export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectP
)}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<select
{...etcProps}
ref={forwardedRef}
@@ -97,7 +148,7 @@ export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectP
height: startingHeight,
}}
className={clsx(
'tesseract-design-menu-select bg-negative rounded-inherit w-full peer block overflow-auto cursor-pointer font-inherit',
'menu-select bg-negative rounded-inherit w-full peer block overflow-auto cursor-pointer font-inherit',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
{
@@ -138,31 +189,6 @@ export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectP
},
)}
/>
{label && (
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 7
categories/choice/react/src/components/RadioButton/RadioButton.css Voir le fichier

@@ -1,7 +0,0 @@
.tesseract-design-radio-button + label > :first-child > :first-child {
display: none;
}

.tesseract-design-radio-button:checked + label > :first-child > :first-child {
display: block;
}

+ 15
- 1
categories/choice/react/src/components/RadioButton/index.tsx Voir le fichier

@@ -1,6 +1,7 @@
import * as React from 'react';
import clsx from 'clsx';
import { Button } from '@tesseract-design/web-base';
import plugin from 'tailwindcss/plugin';

/**
* Derived HTML element of the {@link RadioButton} component.
@@ -37,6 +38,19 @@ export interface RadioButtonProps extends Omit<React.InputHTMLAttributes<RadioBu
variant?: Button.Variant;
}

export const radioButtonPlugin = plugin(({ addComponents }) => {
addComponents({
'.radio-button': {
'& + label > :first-child > :first-child': {
'display': 'none',
},
'&:checked + label > :first-child > :first-child': {
'display': 'block',
},
},
});
});

/**
* Component for selecting a single value from an array of choices grouped by name.
*
@@ -67,7 +81,7 @@ export const RadioButton = React.forwardRef<RadioButtonDerivedElement, RadioButt
ref={forwardedRef}
type="radio"
id={id}
className="sr-only peer tesseract-design-radio-button"
className="sr-only peer radio-button"
/>
<label
style={style}


+ 0
- 7
categories/choice/react/src/components/RadioTickBox/RadioTickBox.css Voir le fichier

@@ -1,7 +0,0 @@
.tesseract-design-radio-tick-box + label + label > :first-child > :first-child {
display: none;
}

.tesseract-design-radio-tick-box:checked + label + label > :first-child > :first-child {
display: block;
}

+ 15
- 1
categories/choice/react/src/components/RadioTickBox/index.tsx Voir le fichier

@@ -1,5 +1,6 @@
import * as React from 'react';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

/**
* Derived HTML element of the {@link RadioTickBox} component.
@@ -20,6 +21,19 @@ export interface RadioTickBoxProps extends Omit<React.InputHTMLAttributes<RadioT
subtext?: React.ReactNode;
}

export const radioTickBoxPlugin = plugin(({ addComponents }) => {
addComponents({
'.radio-tick-box': {
'& + label + label > :first-child > :first-child': {
'display': 'none',
},
'&:checked + label + label > :first-child > :first-child': {
'display': 'block',
},
},
});
});

/**
* Component for selecting a single value from an array of choices grouped by name.
*
@@ -55,7 +69,7 @@ export const RadioTickBox = React.forwardRef<RadioTickBoxDerivedElement, RadioTi
ref={forwardedRef}
type="radio"
id={id}
className="sr-only peer/radio tesseract-design-radio-tick-box"
className="sr-only peer/radio radio-tick-box"
/>
<label
htmlFor={id}


+ 1
- 0
categories/color/react/.eslintrc Voir le fichier

@@ -1,6 +1,7 @@
{
"root": true,
"rules": {
"quote-props": "off",
"react/jsx-props-no-spreading": "off"
},
"extends": [


+ 5
- 6
categories/color/react/package.json Voir le fichier

@@ -27,7 +27,6 @@
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"tslib": "^2.5.0",
"tsx": "^3.12.7",
"typescript": "^4.9.5",
"vitest": "^0.28.1"
},
@@ -37,7 +36,7 @@
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build && tsx scripts/build.ts",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
@@ -63,7 +62,8 @@
"dependencies": {
"clsx": "^1.2.1",
"color": "^4.2.3",
"color-convert": "^2.0.1"
"color-convert": "^2.0.1",
"tailwindcss": "3.3.2"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
@@ -77,10 +77,9 @@
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
},
"./dist/ColorPicker.css": "./dist/ColorPicker.css"
}
},
"typesVersions": {
"*": {}
}
}
}

+ 0
- 19
categories/color/react/scripts/build.ts Voir le fichier

@@ -1,19 +0,0 @@
import { copyFileSync, readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';

const doCopy = (src: string, dest: string) => {
const trueSrc = resolve(src);
const trueDest = resolve(dest);
console.log('Copying...');
console.log(`${trueSrc} -> ${trueDest}`);
copyFileSync(trueSrc, trueDest);
const packageJsonContents = readFileSync('./package.json', 'utf-8');
const packageJson = JSON.parse(packageJsonContents);
packageJson.exports[dest] = dest;
const newPackageJsonContents = JSON.stringify(packageJson, null, 2);
console.log('Updating package.json...');
writeFileSync('./package.json', newPackageJsonContents);
console.log('Done');
}

doCopy('./src/components/ColorPicker/ColorPicker.css', './dist/ColorPicker.css');

+ 0
- 7
categories/color/react/src/components/ColorPicker/ColorPicker.css Voir le fichier

@@ -1,7 +0,0 @@
.color-picker::-webkit-color-swatch-wrapper {
padding: 0;
}

.color-picker::-webkit-color-swatch {
border: 2px solid black;
}

+ 14
- 0
categories/color/react/src/components/ColorPicker/index.tsx Voir le fichier

@@ -1,5 +1,6 @@
import * as React from 'react';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

export type ColorPickerDerivedElement = HTMLInputElement;

@@ -8,6 +9,19 @@ export interface ColorPickerProps extends Omit<React.HTMLProps<ColorPickerDerive
size?: 'small' | 'medium' | 'large';
}

export const colorPickerPlugin = plugin(({ addComponents }) => {
addComponents({
'.color-picker': {
'&::-webkit-color-swatch-wrapper': {
'padding': '0',
},
'&::-webkit-color-swatch': {
'border': '2px solid black',
},
},
});
});

export const ColorPicker = React.forwardRef<
ColorPickerDerivedElement,
ColorPickerProps


+ 28
- 25
categories/formatted/react/src/components/EmailInput/index.tsx Voir le fichier

@@ -93,6 +93,34 @@ export const EmailInput = React.forwardRef<EmailInputDerivedElement, EmailInputP
)}
style={style}
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -133,31 +161,6 @@ export const EmailInput = React.forwardRef<EmailInputDerivedElement, EmailInputP
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
categories/formatted/react/src/components/PatternTextInput/index.tsx Voir le fichier

@@ -104,6 +104,34 @@ export const PatternTextInput = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -144,31 +172,6 @@ export const PatternTextInput = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
categories/formatted/react/src/components/PhoneNumberInput/index.tsx Voir le fichier

@@ -147,6 +147,34 @@ export const PhoneNumberInput = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -171,31 +199,6 @@ export const PhoneNumberInput = React.forwardRef<
className={commonInputStyles}
/>
)}
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
categories/formatted/react/src/components/UrlInput/index.tsx Voir le fichier

@@ -82,6 +82,34 @@ export const UrlInput = React.forwardRef<UrlInputDerivedElement, UrlInputProps>(
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -121,31 +149,6 @@ export const UrlInput = React.forwardRef<UrlInputDerivedElement, UrlInputProps>(
},
)}
/>
{label && (
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
categories/freeform/react/src/components/MaskedTextInput/index.tsx Voir le fichier

@@ -85,6 +85,34 @@ export const MaskedTextInput = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -124,31 +152,6 @@ export const MaskedTextInput = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
categories/freeform/react/src/components/MultilineTextInput/index.tsx Voir le fichier

@@ -82,6 +82,34 @@ export const MultilineTextInput = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<textarea
{...etcProps}
ref={forwardedRef}
@@ -133,31 +161,6 @@ export const MultilineTextInput = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
categories/freeform/react/src/components/TextInput/index.tsx Voir le fichier

@@ -101,6 +101,34 @@ export const TextInput = React.forwardRef<TextInputDerivedElement, TextInputProp
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -141,31 +169,6 @@ export const TextInput = React.forwardRef<TextInputDerivedElement, TextInputProp
},
)}
/>
{label && (
<label
data-testid="label"
htmlFor={id}
id={labelId}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 5
- 10
categories/multichoice/react/package.json Voir le fichier

@@ -28,7 +28,6 @@
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"tslib": "^2.5.0",
"tsx": "^3.12.7",
"typescript": "^4.9.5",
"vitest": "^0.33.0"
},
@@ -38,7 +37,7 @@
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build && tsx scripts/build.ts",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
@@ -65,7 +64,8 @@
"@modal-sh/react-utils": "workspace:*",
"@tesseract-design/web-base": "workspace:*",
"clsx": "^1.2.1",
"react-tag-input-component": "^2.0.2"
"react-tag-input-component": "^2.0.2",
"tailwindcss": "3.3.2"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
@@ -79,14 +79,9 @@
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
},
"./dist/MenuMultiSelect.css": "./dist/MenuMultiSelect.css",
"./dist/TagInput.css": "./dist/TagInput.css",
"./dist/ToggleButton.css": "./dist/ToggleButton.css",
"./dist/ToggleSwitch.css": "./dist/ToggleSwitch.css",
"./dist/ToggleTickBox.css": "./dist/ToggleTickBox.css"
}
},
"typesVersions": {
"*": {}
}
}
}

+ 0
- 23
categories/multichoice/react/scripts/build.ts Voir le fichier

@@ -1,23 +0,0 @@
import { copyFileSync, readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';

const doCopy = (src: string, dest: string) => {
const trueSrc = resolve(src);
const trueDest = resolve(dest);
console.log('Copying...');
console.log(`${trueSrc} -> ${trueDest}`);
copyFileSync(trueSrc, trueDest);
const packageJsonContents = readFileSync('./package.json', 'utf-8');
const packageJson = JSON.parse(packageJsonContents);
packageJson.exports[dest] = dest;
const newPackageJsonContents = JSON.stringify(packageJson, null, 2);
console.log('Updating package.json...');
writeFileSync('./package.json', newPackageJsonContents);
console.log('Done');
}

doCopy('./src/components/MenuMultiSelect/MenuMultiSelect.css', './dist/MenuMultiSelect.css');
doCopy('./src/components/TagInput/TagInput.css', './dist/TagInput.css');
doCopy('./src/components/ToggleButton/ToggleButton.css', './dist/ToggleButton.css');
doCopy('./src/components/ToggleSwitch/ToggleSwitch.css', './dist/ToggleSwitch.css');
doCopy('./src/components/ToggleTickBox/ToggleTickBox.css', './dist/ToggleTickBox.css');

+ 0
- 17
categories/multichoice/react/src/components/MenuMultiSelect/MenuMultiSelect.css Voir le fichier

@@ -1,17 +0,0 @@
.tesseract-design-menu-multi-select optgroup {
color: rgb(var(--color-positive) / 50%);
text-transform: uppercase;
font-size: 0.75em;
margin-top: 0.5rem;
user-select: none;
}

.tesseract-design-menu-multi-select optgroup > option {
color: rgb(var(--color-positive));
text-transform: none;
font-size: 1.333333em;
}

.tesseract-design-menu-multi-select option {
user-select: none;
}

+ 52
- 26
categories/multichoice/react/src/components/MenuMultiSelect/index.tsx Voir le fichier

@@ -1,6 +1,7 @@
import * as React from 'react';
import { TextControl } from '@tesseract-design/web-base';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

export type MenuMultiSelectDerivedElement = HTMLSelectElement;

@@ -43,6 +44,28 @@ export interface MenuMultiSelectProps extends Omit<React.HTMLProps<MenuMultiSele
startingHeight?: number | string,
}

export const menuMultiSelectPlugin = plugin(({ addComponents, }) => {
addComponents({
'.menu-multi-select': {
'& optgroup': {
'color': 'rgb(var(--color-positive) / 50%)',
'text-transform': 'uppercase',
'font-size': '0.75em',
'margin-top': '0.5rem',
'user-select': 'none',
},
'& optgroup > option': {
'color': 'rgb(var(--color-positive))',
'text-transform': 'none',
'font-size': '1.333333em',
},
'& option': {
'user-select': 'none',
},
},
});
});

/**
* Component for inputting textual values.
*
@@ -75,7 +98,7 @@ export const MenuMultiSelect = React.forwardRef<
return (
<div
className={clsx(
'tesseract-design-menu-multi-select relative rounded ring-secondary/50',
'menu-multi-select relative rounded ring-secondary/50',
'focus-within:ring-4',
{
'block': block,
@@ -85,6 +108,34 @@ export const MenuMultiSelect = React.forwardRef<
)}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<select
{...etcProps}
ref={forwardedRef}
@@ -138,31 +189,6 @@ export const MenuMultiSelect = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 109
categories/multichoice/react/src/components/TagInput/TagInput.css Voir le fichier

@@ -1,109 +0,0 @@
.tesseract-design-tag-input textarea + div > input {
flex: auto;
}
.tesseract-design-tag-input.tag-input-small textarea + div > input {
font-size: 0.625rem;
}

.tesseract-design-tag-input.tag-input-medium textarea + div > input {
font-size: 0.75rem;
}

.tesseract-design-tag-input.tag-input-default textarea + div {
padding-left: 1rem;
padding-right: 1rem;
}

.tesseract-design-tag-input.tag-input-alternate textarea + div {
padding-left: 0.375rem;
padding-right: 0.375rem;
}

.tesseract-design-tag-input.tag-input-small.tag-input-default textarea + div {
padding-top: 0.625rem;
padding-bottom: 0.875rem;
}

.tesseract-design-tag-input.tag-input-medium.tag-input-default textarea + div {
padding-top: 0.75rem;
padding-bottom: 1rem;
}

.tesseract-design-tag-input.tag-input-large.tag-input-default textarea + div {
padding-top: 1rem;
padding-bottom: 1.25rem;
}

.tesseract-design-tag-input.tag-input-small.tag-input-alternate textarea + div {
padding-top: 1.375rem;
}

.tesseract-design-tag-input.tag-input-medium.tag-input-alternate textarea + div {
padding-top: 1.5rem;
}

.tesseract-design-tag-input.tag-input-large.tag-input-alternate textarea + div {
padding-top: 1.75rem;
}

.tesseract-design-tag-input.tag-input-small textarea + div {
gap: 0.25rem;
min-height: 2.5rem;
}

.tesseract-design-tag-input.tag-input-small.tag-input-indicator textarea + div {
padding-right: 2.5rem;
}

.tesseract-design-tag-input.tag-input-medium textarea + div {
gap: 0.375rem;
min-height: 3rem;
}

.tesseract-design-tag-input.tag-input-medium.tag-input-indicator textarea + div {
padding-right: 3rem;
}

.tesseract-design-tag-input.tag-input-large textarea + div {
gap: 0.375rem;
min-height: 4rem;
}

.tesseract-design-tag-input.tag-input-large.tag-input-indicator textarea + div {
padding-right: 4rem;
}

.tesseract-design-tag-input textarea + div > span {
padding: 0.125rem;
border-radius: 0.25rem;
line-height: 1;
background-color: rgb(var(--color-positive) / 25%);
}

.tesseract-design-tag-input textarea + div > span:focus-within {
background-color: rgb(var(--color-secondary) / 25%);
}

.tesseract-design-tag-input textarea + div > span span {
pointer-events: none;
}

.tesseract-design-tag-input textarea + div > span button {
color: rgb(var(--color-primary));
padding: 0;
width: 1rem;
margin-left: 0.25rem;
}

.tesseract-design-tag-input textarea + div > span button:focus {
outline: none;
color: rgb(var(--color-secondary));
}

.tesseract-design-tag-input textarea + div > span button:focus:-moz-focusring {
display: none;
}

.tesseract-design-tag-input textarea + div > span button:hover {
color: rgb(var(--color-primary));
}

+ 146
- 31
categories/multichoice/react/src/components/TagInput/index.tsx Voir le fichier

@@ -3,6 +3,7 @@ import { TagsInput } from 'react-tag-input-component';
import clsx from 'clsx';
import { useClientSide, delegateTriggerEvent } from '@modal-sh/react-utils';
import { TextControl } from '@tesseract-design/web-base';
import plugin from 'tailwindcss/plugin';

const TAG_INPUT_SEPARATOR_MAP = {
'comma': ',',
@@ -61,6 +62,120 @@ export interface TagInputProps extends Omit<React.HTMLProps<TagInputDerivedEleme
editOnRemove?: boolean,
}

export const tagInputPlugin = plugin(({ addComponents }) => {
addComponents({
'.tag-input': {
'& textarea + div > input': {
'flex': 'auto',
},
'&[data-size="small"] textarea + div > input': {
'font-size': '0.625rem',
},
'&[data-size="medium"] textarea + div > input': {
'font-size': '0.75rem',
},
'&[data-variant="default"] textarea + div': {
'padding-left': '1rem',
'padding-right': '1rem',
},

'&[data-variant="alternate"] textarea + div': {
'padding-left': '0.375rem',
'padding-right': '0.375rem',
},

'&[data-size="small"][data-variant="default"] textarea + div': {
'padding-top': '0.625rem',
'padding-bottom': '0.875rem',
},

'&[data-size="medium"][data-variant="default"] textarea + div': {
'padding-top': '0.75rem',
'padding-bottom': '1rem',
},

'&[data-size="large"][data-variant="default"] textarea + div': {
'padding-top': '1rem',
'padding-bottom': '1.25rem',
},

'&[data-size="small"][data-variant="alternate"] textarea + div': {
'padding-top': '1.375rem',
},

'&[data-size="medium"][data-variant="alternate"] textarea + div': {
'padding-top': '1.5rem',
},

'&[data-size="large"][data-variant="alternate"] textarea + div': {
'padding-top': '1.75rem',
},

'&[data-size="small"] textarea + div': {
'gap': '0.25rem',
'min-height': '2.5rem',
},

'&[data-size="small"].tag-input-indicator textarea + div': {
'padding-right': '2.5rem',
},

'&[data-size="medium"] textarea + div': {
'gap': '0.375rem',
'min-height': '3rem',
},

'&[data-size="medium"].tag-input-indicator textarea + div': {
'padding-right': '3rem',
},

'&[data-size="large"] textarea + div': {
'gap': '0.375rem',
'min-height': '4rem',
},

'&[data-size="large"].tag-input-indicator textarea + div': {
'padding-right': '4rem',
},

'& textarea + div > span': {
'padding': '0.125rem',
'border-radius': '0.25rem',
'line-height': '1',
'background-color': 'rgb(var(--color-positive) / 25%)',
},

'& textarea + div > span:focus-within': {
'background-color': 'rgb(var(--color-secondary) / 25%)',
},

'& textarea + div > span span': {
'pointer-events': 'none',
},

'& textarea + div > span button': {
'color': 'rgb(var(--color-primary))',
'padding': '0',
'width': '1rem',
'margin-left': '0.25rem',
},

'& textarea + div > span button:focus': {
'outline': 'none',
'color': 'rgb(var(--color-secondary))',
},

'& textarea + div > span button:focus:-moz-focusring': {
'display': 'none',
},

'& textarea + div > span button:hover': {
'color': 'rgb(var(--color-primary))',
},
},
});
});

/**
* Component for inputting textual values.
*
@@ -203,6 +318,8 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>(

return (
<div
data-size={size}
data-variant={variant}
className={clsx(
'relative rounded ring-secondary/50 group',
'focus-within:ring-4',
@@ -215,18 +332,41 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>(
'min-h-12': size === 'medium',
'min-h-16': size === 'large',
},
'tesseract-design-tag-input',
size === 'small' && 'tag-input-small',
size === 'medium' && 'tag-input-medium',
size === 'large' && 'tag-input-large',
'tag-input',
indicator && 'tag-input-indicator',
variant === 'default' && 'tag-input-default',
variant === 'alternate' && 'tag-input-alternate',
className,
)}
data-testid="base"
onFocusCapture={handleFocusCapture}
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 group-focus-within:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<textarea
{...etcProps}
placeholder={placeholder}
@@ -303,31 +443,6 @@ export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>(
separators={separator.map((s) => TAG_INPUT_SEPARATOR_MAP[s])}
/>
)}
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 group-focus-within:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 15
categories/multichoice/react/src/components/ToggleButton/ToggleButton.css Voir le fichier

@@ -1,15 +0,0 @@
.tesseract-design-toggle-button + label > :first-child > :first-child {
display: none;
}

.tesseract-design-toggle-button:checked + label > :first-child > :first-child {
display: block;
}

.tesseract-design-toggle-button + label > :first-child > :first-child + * {
display: none;
}

.tesseract-design-toggle-button:indeterminate + label > :first-child > :first-child + * {
display: block;
}

+ 21
- 1
categories/multichoice/react/src/components/ToggleButton/index.tsx Voir le fichier

@@ -1,6 +1,7 @@
import * as React from 'react';
import clsx from 'clsx';
import { Button } from '@tesseract-design/web-base';
import plugin from 'tailwindcss/plugin';

export type ToggleButtonDerivedElement = HTMLInputElement;

@@ -14,6 +15,25 @@ export interface ToggleButtonProps extends Omit<React.InputHTMLAttributes<Toggle
indeterminate?: boolean;
}

export const toggleButtonPlugin = plugin(({ addComponents, }) => {
addComponents({
'.toggle-button': {
'& + label > :first-child > :first-child': {
'display': 'none',
},
'&:checked + label > :first-child > :first-child': {
'display': 'block',
},
'& + label > :first-child > :first-child + *': {
'display': 'none',
},
'&:indeterminate + label > :first-child > :first-child + *': {
'display': 'block',
},
},
});
});

export const ToggleButton = React.forwardRef<ToggleButtonDerivedElement, ToggleButtonProps>((
{
children,
@@ -53,7 +73,7 @@ export const ToggleButton = React.forwardRef<ToggleButtonDerivedElement, ToggleB
ref={typeof ref === 'function' ? defaultRef : ref}
type="checkbox"
id={id}
className="sr-only peer tesseract-design-toggle-button"
className="sr-only peer toggle-button"
/>
<label
data-testid="button"


+ 0
- 118
categories/multichoice/react/src/components/ToggleSwitch/ToggleSwitch.css Voir le fichier

@@ -1,118 +0,0 @@
.tesseract-design-toggle-switch + label + label + label > :first-child {
appearance: none;
cursor: pointer;
position: relative;
overflow: hidden;
height: 1.5em;
width: 3em;
display: block;
box-sizing: border-box;
border-radius: 9999px;
color: rgb(var(--color-primary));
}

.tesseract-design-toggle-switch:checked + label + label + label > :first-child {
color: rgb(var(--color-tertiary));
}

.tesseract-design-toggle-switch:focus + label + label + label > :first-child {
color: rgb(var(--color-secondary));
}

.tesseract-design-toggle-switch + label:active + label + label > :first-child {
color: rgb(var(--color-tertiary));
}

.tesseract-design-toggle-switch + label + label:active + label > :first-child {
color: rgb(var(--color-tertiary));
}

.tesseract-design-toggle-switch + label + label + label:active > :first-child {
color: rgb(var(--color-tertiary));
}

.tesseract-design-toggle-switch + label + label + label > :first-child > :first-child {
width: 100%;
height: 100%;
background-color: rgb(var(--color-primary) / 50%);
border-radius: 9999px;
display: block;
box-sizing: border-box;
background-clip: content-box;
padding: 0.25em;
appearance: none;
}

.tesseract-design-toggle-switch:checked + label + label + label > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch:focus + label + label + label > :first-child > :first-child {
background-color: rgb(var(--color-secondary) / 50%);
}

.tesseract-design-toggle-switch + label:active + label + label > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch + label + label:active + label > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch + label + label + label:active > :first-child > :first-child {
background-color: rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch + label + label + label > :first-child > :first-child > :first-child {
appearance: none;
border-radius: 9999px;
display: block;
width: 100%;
height: 100%;
margin: -0.25em;
box-sizing: border-box;
background-clip: content-box;
}

.tesseract-design-toggle-switch + label + label + label > :first-child > :first-child > :first-child > :first-child {
width: 1.5em;
height: 1.5em;
margin: -0.25em 0 0 0;
display: block;
border-radius: 9999px;
background-color: currentColor;
appearance: none;
aspect-ratio: 1 / 1;
z-index: 1;
position: relative;
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-primary) / 50%);
}

.tesseract-design-toggle-switch:checked + label + label + label > :first-child > :first-child > :first-child > :first-child {
margin-left: calc(100% - 1em);
}

.tesseract-design-toggle-switch:indeterminate + label + label + label > :first-child > :first-child > :first-child > :first-child {
margin-left: calc(50% - 0.5em);
}

.tesseract-design-toggle-switch:checked + label + label + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch:focus + label + label + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%);
}

.tesseract-design-toggle-switch + label:active + label + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch + label + label:active + label > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-toggle-switch + label + label + label:active > :first-child > :first-child > :first-child > :first-child {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}


+ 123
- 1
categories/multichoice/react/src/components/ToggleSwitch/index.tsx Voir le fichier

@@ -1,5 +1,6 @@
import * as React from 'react';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

export type ToggleSwitchDerivedElement = HTMLInputElement;

@@ -11,6 +12,127 @@ export interface ToggleSwitchProps extends Omit<React.InputHTMLAttributes<Toggle
uncheckedLabel?: React.ReactNode;
}

export const toggleSwitchPlugin = plugin(({ addComponents }) => {
addComponents({
'.toggle-switch': {
'& + label + label + label > :first-child': {
appearance: 'none',
cursor: 'pointer',
position: 'relative',
overflow: 'hidden',
height: '1.5em',
width: '3em',
display: 'block',
'box-sizing': 'border-box',
'border-radius': '9999px',
color: 'rgb(var(--color-primary))',
},

'&:checked + label + label + label > :first-child': {
color: 'rgb(var(--color-tertiary))',
},

'&:focus + label + label + label > :first-child': {
color: 'rgb(var(--color-secondary))',
},

'& + label:active + label + label > :first-child': {
color: 'rgb(var(--color-tertiary))',
},

'& + label + label:active + label > :first-child': {
color: 'rgb(var(--color-tertiary))',
},

'& + label + label + label:active > :first-child': {
color: 'rgb(var(--color-tertiary))',
},

'& + label + label + label > :first-child > :first-child': {
width: '100%',
height: '100%',
'background-color': 'rgb(var(--color-primary) / 50%)',
'border-radius': '9999px',
display: 'block',
'box-sizing': 'border-box',
'background-clip': 'content-box',
padding: '0.25em',
appearance: 'none',
},

'&:checked + label + label + label > :first-child > :first-child': {
'background-color': 'rgb(var(--color-tertiary) / 50%)',
},

'&:focus + label + label + label > :first-child > :first-child': {
'background-color': 'rgb(var(--color-secondary) / 50%)',
},

'& + label:active + label + label > :first-child > :first-child': {
'background-color': 'rgb(var(--color-tertiary) / 50%)',
},

'& + label + label:active + label > :first-child > :first-child': {
'background-color': 'rgb(var(--color-tertiary) / 50%)',
},

'& + label + label + label:active > :first-child > :first-child': {
'background-color': 'rgb(var(--color-tertiary) / 50%)',
},

'& + label + label + label > :first-child > :first-child > :first-child': {
appearance: 'none',
'border-radius': '9999px',
display: 'block',
width: '100%',
height: '100%',
margin: '-0.25em',
'box-sizing': 'border-box',
'background-clip': 'content-box',
},

'& + label + label + label > :first-child > :first-child > :first-child > :first-child': {
width: '1.5em',
height: '1.5em',
margin: '-0.25em 0 0 0',
display: 'block',
'border-radius': '9999px',
'background-color': 'currentColor',
appearance: 'none',
'aspect-ratio': '1 / 1',
'z-index': '1',
position: 'relative',
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-primary) / 50%)',
},

'&:checked + label + label + label > :first-child > :first-child > :first-child > :first-child': {
'margin-left': 'calc(100% - 1em)',
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%)',
},

'&:indeterminate + label + label + label > :first-child > :first-child > :first-child > :first-child': {
'margin-left': 'calc(50% - 0.5em)',
},

'&:focus + label + label + label > :first-child > :first-child > :first-child > :first-child': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%)',
},

'& + label:active + label + label > :first-child > :first-child > :first-child > :first-child': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%)',
},

'& + label + label:active + label > :first-child > :first-child > :first-child > :first-child': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%)',
},

'& + label + label + label:active > :first-child > :first-child > :first-child > :first-child': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%)',
},
},
});
});

export const ToggleSwitch = React.forwardRef<ToggleSwitchDerivedElement, ToggleSwitchProps>((
{
uncheckedLabel,
@@ -57,7 +179,7 @@ export const ToggleSwitch = React.forwardRef<ToggleSwitchDerivedElement, ToggleS
ref={typeof ref === 'function' ? defaultRef : ref}
type="checkbox"
id={id}
className="sr-only peer/radio tesseract-design-toggle-switch"
className="sr-only peer/radio toggle-switch"
/>
<label
htmlFor={id}


+ 0
- 15
categories/multichoice/react/src/components/ToggleTickBox/ToggleTickBox.css Voir le fichier

@@ -1,15 +0,0 @@
.tesseract-design-toggle-tick-box + label + label > :first-child > :first-child {
display: none;
}

.tesseract-design-toggle-tick-box:checked + label + label > :first-child > :first-child {
display: block;
}

.tesseract-design-toggle-tick-box + label + label > :first-child > :first-child + * {
display: none;
}

.tesseract-design-toggle-tick-box:indeterminate + label + label > :first-child > :first-child + * {
display: block;
}

+ 21
- 1
categories/multichoice/react/src/components/ToggleTickBox/index.tsx Voir le fichier

@@ -1,5 +1,6 @@
import * as React from 'react';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

export type ToggleTickBoxDerivedElement = HTMLInputElement;

@@ -9,6 +10,25 @@ export interface ToggleTickBoxProps extends Omit<React.InputHTMLAttributes<Toggl
indeterminate?: boolean;
}

export const toggleTickBoxPlugin = plugin(({ addComponents, }) => {
addComponents({
'.toggle-tick-box': {
'& + label + label > :first-child > :first-child': {
'display': 'none',
},
'&:checked + label + label > :first-child > :first-child': {
'display': 'block',
},
'& + label + label > :first-child > :first-child + *': {
'display': 'none',
},
'&:indeterminate + label + label > :first-child > :first-child + *': {
'display': 'block',
},
},
});
});

export const ToggleTickBox = React.forwardRef<ToggleTickBoxDerivedElement, ToggleTickBoxProps>((
{
children,
@@ -54,7 +74,7 @@ export const ToggleTickBox = React.forwardRef<ToggleTickBoxDerivedElement, Toggl
ref={typeof ref === 'function' ? defaultRef : ref}
type="checkbox"
id={id}
className="sr-only peer/radio tesseract-design-toggle-tick-box"
className="sr-only peer/radio toggle-tick-box"
/>
<label
htmlFor={id}


+ 5
- 7
categories/number/react/package.json Voir le fichier

@@ -28,7 +28,6 @@
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"tslib": "^2.5.0",
"tsx": "^3.12.7",
"typescript": "^4.9.5",
"vitest": "^0.33.0"
},
@@ -38,7 +37,7 @@
},
"scripts": {
"prepublishOnly": "pridepack clean && pridepack build",
"build": "pridepack build && tsx scripts/build.ts",
"build": "pridepack build",
"type-check": "pridepack check",
"lint": "pridepack lint",
"clean": "pridepack clean",
@@ -63,7 +62,8 @@
},
"dependencies": {
"@tesseract-design/web-base": "workspace:*",
"clsx": "^1.2.1"
"clsx": "^1.2.1",
"tailwindcss": "3.3.2"
},
"types": "./dist/types/index.d.ts",
"main": "./dist/cjs/production/index.js",
@@ -77,11 +77,9 @@
"require": "./dist/cjs/production/index.js",
"import": "./dist/esm/production/index.js",
"types": "./dist/types/index.d.ts"
},
"./dist/Slider.css": "./dist/Slider.css",
"./dist/NumberSpinner.css": "./dist/NumberSpinner.css"
}
},
"typesVersions": {
"*": {}
}
}
}

+ 0
- 20
categories/number/react/scripts/build.ts Voir le fichier

@@ -1,20 +0,0 @@
import { copyFileSync, readFileSync, writeFileSync } from 'fs';
import { resolve } from 'path';

const doCopy = (src: string, dest: string) => {
const trueSrc = resolve(src);
const trueDest = resolve(dest);
console.log('Copying...');
console.log(`${trueSrc} -> ${trueDest}`);
copyFileSync(trueSrc, trueDest);
const packageJsonContents = readFileSync('./package.json', 'utf-8');
const packageJson = JSON.parse(packageJsonContents);
packageJson.exports[dest] = dest;
const newPackageJsonContents = JSON.stringify(packageJson, null, 2);
console.log('Updating package.json...');
writeFileSync('./package.json', newPackageJsonContents);
console.log('Done');
}

doCopy('./src/components/Slider/Slider.css', './dist/Slider.css');
doCopy('./src/components/NumberSpinner/NumberSpinner.css', './dist/NumberSpinner.css');

+ 0
- 12
categories/number/react/src/components/NumberSpinner/NumberSpinner.css Voir le fichier

@@ -1,12 +0,0 @@
.tesseract-design-number-spinner {
position: relative;
}

.tesseract-design-number-spinner::-webkit-inner-spin-button {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 1.5rem;
z-index: 2;
}

+ 46
- 27
categories/number/react/src/components/NumberSpinner/index.tsx Voir le fichier

@@ -1,6 +1,7 @@
import * as React from 'react';
import { TextControl } from '@tesseract-design/web-base';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

export type NumberSpinnerDerivedElement = HTMLInputElement;

@@ -43,6 +44,21 @@ export interface NumberSpinnerProps extends Omit<React.HTMLProps<NumberSpinnerDe
length?: number,
}

export const numberSpinnerPlugin = plugin(({ addComponents, }) => {
addComponents({
'.number-spinner': {
'&::-webkit-inner-spin-button': {
'position': 'absolute',
'top': '0',
'right': '0',
'height': '100%',
'width': '1.5rem',
'z-index': '2',
},
},
});
});

/**
* Component for inputting numeric values.
*/
@@ -82,6 +98,34 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -91,10 +135,10 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe
type="number"
data-testid="input"
className={clsx(
'bg-negative rounded-inherit w-full peer block tabular-nums font-inherit',
'bg-negative rounded-inherit w-full peer block tabular-nums font-inherit relative',
'focus:outline-0',
'disabled:opacity-50 disabled:cursor-not-allowed',
'tesseract-design-number-spinner',
'number-spinner',
{
'text-xxs': size === 'small',
'text-xs': size === 'medium',
@@ -122,31 +166,6 @@ export const NumberSpinner = React.forwardRef<NumberSpinnerDerivedElement, Numbe
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 157
categories/number/react/src/components/Slider/Slider.css Voir le fichier

@@ -1,157 +0,0 @@
.tesseract-design-slider-wrapper > input {
appearance: none;
cursor: pointer;
position: relative;
overflow: hidden;
height: 1em;
box-sizing: border-box;
color: rgb(var(--color-primary));
}

.tesseract-design-slider-wrapper > input::-webkit-slider-container {
width: 100%;
height: 100%;
min-block-size: 0;
background-color: rgb(var(--color-primary) / 50%);
border-radius: 9999px;
display: block;
box-sizing: border-box;
background-clip: content-box;
padding: 0.25em;
appearance: none;
}

.tesseract-design-slider-wrapper > input::-webkit-slider-runnable-track {
appearance: none;
border-radius: 9999px;
display: block;
width: 100%;
height: 100%;
margin: -0.25em;
box-sizing: border-box;
background-clip: content-box;
}

.tesseract-design-slider-wrapper > input::-webkit-slider-thumb {
width: 1em;
height: 1em;
margin: -0.25em 0 0 0;

border-radius: 9999px;
background-color: currentColor;
appearance: none;
aspect-ratio: 1 / 1;
z-index: 1;
position: relative;
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-primary) / 50%);
}

.tesseract-design-slider-wrapper > input:focus::-webkit-slider-container {
background-color: rgb(var(--color-secondary) / 50%);
}

.tesseract-design-slider-wrapper > input:active::-webkit-slider-container {
background-color: rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-slider-wrapper > input:focus::-webkit-slider-thumb {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%);
}

.tesseract-design-slider-wrapper > input:active::-webkit-slider-thumb {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-slider-wrapper[data-orient='horizontal'] {
flex-direction: column;
}

.tesseract-design-slider-wrapper[data-firefox] {
flex-direction: column;
}

.tesseract-design-slider-wrapper[data-firefox='vertical'] {
flex-direction: row;
}

.tesseract-design-slider-wrapper[data-orient='vertical'] {
flex-direction: column;
rotate: -90deg;
translate: calc(-100% + 0.5em * 2);
transform-origin: calc(100% - 0.5em) 0.5em;
}

.tesseract-design-slider-wrapper > input::-moz-range-track {
appearance: none;
border-radius: 9999px;
content: '';
display: block;
position: absolute;
background-color: currentColor;
opacity: 0.5;
width: calc(100% - 0.5em);
height: 50%;
top: 25%;
margin: -0.25em;
}

.tesseract-design-slider-wrapper > input::-moz-range-thumb {
height: 100%;
outline: 0;
border: 0;

border-radius: 9999px;
background-color: currentColor;
appearance: none;
aspect-ratio: 1 / 1;
z-index: 1;
position: relative;
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-primary) / 50%);
}

.tesseract-design-slider-wrapper > input:focus::-moz-range-thumb {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%);
}

.tesseract-design-slider-wrapper > input:active::-moz-range-thumb {
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-slider-wrapper > input[orient='vertical'] {
width: 1em;
height: 16em;
}

.tesseract-design-slider-wrapper > input[orient='vertical']::-moz-range-track {
width: 50%;
height: calc(100% - 0.5em);
}

.tesseract-design-slider-wrapper > input[orient='vertical']::-moz-range-thumb {
width: 100%;
height: 1em;
box-shadow: 0 100000.5em 0 100000em rgb(var(--color-primary) / 50%);
}

.tesseract-design-slider-wrapper > input[orient='vertical']:focus::-moz-range-thumb {
box-shadow: 0 100000.5em 0 100000em rgb(var(--color-secondary) / 50%);
}

.tesseract-design-slider-wrapper > input[orient='vertical']:active::-moz-range-thumb {
box-shadow: 0 100000.5em 0 100000em rgb(var(--color-tertiary) / 50%);
}

.tesseract-design-slider-wrapper[data-chrome] > input + * {
padding: 0 0.5em;
height: 1.5em;
}

.tesseract-design-slider-wrapper[data-firefox='horizontal'] > input + * {
padding: 0 0.5em;
height: 1.5em;
}

.tesseract-design-slider-wrapper[data-firefox='vertical'] > input + * {
padding: 0.5em 0;
width: 1.5em;
}

+ 164
- 1
categories/number/react/src/components/Slider/index.tsx Voir le fichier

@@ -1,5 +1,6 @@
import * as React from 'react';
import clsx from 'clsx';
import plugin from 'tailwindcss/plugin';

const filterOptions = (children: React.ReactNode): React.ReactNode => {
const childrenArray = Array.isArray(children) ? children : [children];
@@ -44,6 +45,168 @@ export interface SliderProps extends Omit<React.HTMLProps<HTMLInputElement>, 'ty
length?: React.CSSProperties['width'];
}

export const sliderPlugin = plugin(({ addComponents }) => {
addComponents({
'.slider': {
'& > input': {
appearance: 'none',
cursor: 'pointer',
position: 'relative',
overflow: 'hidden',
height: '1em',
'box-sizing': 'border-box',
color: 'rgb(var(--color-primary))',
},

'& > input::-webkit-slider-container': {
width: '100%',
height: '100%',
'min-block-size': '0',
'background-color': 'rgb(var(--color-primary) / 50%)',
'border-radius': '9999px',
display: 'block',
'box-sizing': 'border-box',
'background-clip': 'content-box',
padding: '0.25em',
appearance: 'none',
},

'& > input::-webkit-slider-runnable-track': {
appearance: 'none',
'border-radius': '9999px',
display: 'block',
width: '100%',
height: '100%',
margin: '-0.25em',
'box-sizing': 'border-box',
'background-clip': 'content-box',
},

'& > input::-webkit-slider-thumb': {
width: '1em',
height: '1em',
margin: '-0.25em 0 0 0',
'border-radius': '9999px',
'background-color': 'currentColor',
appearance: 'none',
'aspect-ratio': '1 / 1',
'z-index': '1',
position: 'relative',
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-primary) / 50%)',
},

'& > input:focus::-webkit-slider-container': {
'background-color': 'rgb(var(--color-secondary) / 50%)',
},

'& > input:active::-webkit-slider-container': {
'background-color': 'rgb(var(--color-tertiary) / 50%)',
},

'& > input:focus::-webkit-slider-thumb': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%)',
},

'& > input:active::-webkit-slider-thumb': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%)',
},

'&[data-orient="horizontal"]': {
'flex-direction': 'column',
},

'&[data-firefox]': {
'flex-direction': 'column',
},

'&[data-firefox="vertical"]': {
'flex-direction': 'row',
},

'&[data-orient="vertical"]': {
'flex-direction': 'column',
'rotate': '-90deg',
'translate': 'calc(-100% + 0.5em * 2)',
'transform-origin': 'calc(100% - 0.5em) 0.5em',
},

'& > input::-moz-range-track': {
appearance: 'none',
'border-radius': '9999px',
'content': '""',
display: 'block',
position: 'absolute',
'background-color': 'currentColor',
'opacity': '0.5',
width: 'calc(100% - 0.5em)',
height: '50%',
top: '25%',
margin: '-0.25em',
},

'& > input::-moz-range-thumb': {
height: '100%',
outline: '0',
border: '0',
'border-radius': '9999px',
'background-color': 'currentColor',
appearance: 'none',
'aspect-ratio': '1 / 1',
'z-index': '1',
position: 'relative',
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-primary) / 50%)',
},

'& > input:focus::-moz-range-thumb': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-secondary) / 50%)',
},

'& > input:active::-moz-range-thumb': {
'box-shadow': '-100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%)',
},

'& > input[orient="vertical"]': {
width: '1em',
height: '16em',
},

'& > input[orient="vertical"]::-moz-range-track': {
width: '50%',
height: 'calc(100% - 0.5em)',
},

'& > input[orient="vertical"]::-moz-range-thumb': {
width: '100%',
height: '1em',
'box-shadow': '0 100000.5em 0 100000em rgb(var(--color-primary) / 50%)',
},

'& > input[orient="vertical"]:focus::-moz-range-thumb': {
'box-shadow': '0 100000.5em 0 100000em rgb(var(--color-secondary) / 50%)',
},

'& > input[orient="vertical"]:active::-moz-range-thumb': {
'box-shadow': '0 100000.5em 0 100000em rgb(var(--color-tertiary) / 50%)',
},

'&[data-chrome] > input + *': {
'padding': '0 0.5em',
'height': '1.5em',
},

'&[data-firefox="horizontal"] > input + *': {
'padding': '0 0.5em',
'height': '1.5em',
},

'&[data-firefox="vertical"] > input + *': {
'padding': '0.5em 0',
'width': '1.5em',
},
},
});
});

export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>((
{
className,
@@ -274,7 +437,7 @@ export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>((
}}
>
<div
className="flex tesseract-design-slider-wrapper"
className="flex slider"
data-orient={orient}
>
<input


+ 28
- 25
categories/temporal/react/src/components/DateDropdown/index.tsx Voir le fichier

@@ -85,6 +85,34 @@ export const DateDropdown = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
size={length}
@@ -125,31 +153,6 @@ export const DateDropdown = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 12
- 12
pnpm-lock.yaml Voir le fichier

@@ -151,6 +151,9 @@ importers:
clsx:
specifier: ^1.2.1
version: 1.2.1
tailwindcss:
specifier: 3.3.2
version: 3.3.2
devDependencies:
'@testing-library/jest-dom':
specifier: ^5.16.5
@@ -197,9 +200,6 @@ importers:
tslib:
specifier: ^2.5.0
version: 2.6.0
tsx:
specifier: ^3.12.7
version: 3.12.7
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -218,6 +218,9 @@ importers:
color-convert:
specifier: ^2.0.1
version: 2.0.1
tailwindcss:
specifier: 3.3.2
version: 3.3.2
devDependencies:
'@testing-library/jest-dom':
specifier: ^5.16.5
@@ -261,9 +264,6 @@ importers:
tslib:
specifier: ^2.5.0
version: 2.6.0
tsx:
specifier: ^3.12.7
version: 3.12.7
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -462,6 +462,9 @@ importers:
react-tag-input-component:
specifier: ^2.0.2
version: 2.0.2(react-dom@18.2.0)(react@18.2.0)
tailwindcss:
specifier: 3.3.2
version: 3.3.2
devDependencies:
'@testing-library/jest-dom':
specifier: ^5.16.5
@@ -508,9 +511,6 @@ importers:
tslib:
specifier: ^2.5.0
version: 2.6.0
tsx:
specifier: ^3.12.7
version: 3.12.7
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -587,6 +587,9 @@ importers:
clsx:
specifier: ^1.2.1
version: 1.2.1
tailwindcss:
specifier: 3.3.2
version: 3.3.2
devDependencies:
'@testing-library/jest-dom':
specifier: ^5.16.5
@@ -633,9 +636,6 @@ importers:
tslib:
specifier: ^2.5.0
version: 2.6.0
tsx:
specifier: ^3.12.7
version: 3.12.7
typescript:
specifier: ^4.9.5
version: 4.9.5


+ 28
- 25
showcases/web-kitchensink-reactnext/src/components/temporal/TimeSpinner/index.tsx Voir le fichier

@@ -103,6 +103,34 @@ export const TimeSpinner = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
ref={forwardedRef}
@@ -143,31 +171,6 @@ export const TimeSpinner = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
showcases/web-kitchensink-reactnext/src/components/temporal/WeekInput/index.tsx Voir le fichier

@@ -82,6 +82,34 @@ export const WeekInput = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
ref={forwardedRef}
@@ -121,31 +149,6 @@ export const WeekInput = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 28
- 25
showcases/web-kitchensink-reactnext/src/components/temporal/YearMonthInput/index.tsx Voir le fichier

@@ -82,6 +82,34 @@ export const YearMonthInput = React.forwardRef<
style={style}
data-testid="base"
>
{label && (
<>
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
{' '}
</>
)}
<input
{...etcProps}
ref={forwardedRef}
@@ -121,31 +149,6 @@ export const YearMonthInput = React.forwardRef<
},
)}
/>
{label && (
<label
data-testid="label"
id={labelId}
htmlFor={id}
className={clsx(
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative select-none',
{
'sr-only': hiddenLabel,
},
{
'pr-1': !indicator,
},
{
'pr-10': indicator && size === 'small',
'pr-12': indicator && size === 'medium',
'pr-16': indicator && size === 'large',
},
)}
>
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis">
{label}
</span>
</label>
)}
{hint && (
<div
data-testid="hint"


+ 0
- 16
showcases/web-kitchensink-reactnext/src/pages/_app.tsx Voir le fichier

@@ -1,22 +1,6 @@
import '@/styles/globals.css'
import '@/styles/kitchen-sink.css'

import '@tesseract-design/web-choice-react/dist/DropdownSelect.css'
import '@tesseract-design/web-choice-react/dist/MenuSelect.css'
import '@tesseract-design/web-choice-react/dist/RadioButton.css'
import '@tesseract-design/web-choice-react/dist/RadioTickBox.css'

import '@tesseract-design/web-color-react/dist/ColorPicker.css'

import '@tesseract-design/web-multichoice-react/dist/MenuMultiSelect.css'
import '@tesseract-design/web-multichoice-react/dist/TagInput.css'
import '@tesseract-design/web-multichoice-react/dist/ToggleButton.css'
import '@tesseract-design/web-multichoice-react/dist/ToggleSwitch.css'
import '@tesseract-design/web-multichoice-react/dist/ToggleTickBox.css'

import '@tesseract-design/web-number-react/dist/NumberSpinner.css'
import '@tesseract-design/web-number-react/dist/Slider.css'

import '@modal-sh/react-refractor/dist/Refractor.css'

import type { AppProps } from 'next/app'


+ 17
- 0
showcases/web-kitchensink-reactnext/src/pages/categories/color/index.tsx Voir le fichier

@@ -38,6 +38,23 @@ const ColorPage: NextPage = () => {
defaultValue="#0000ff"
/>
</Subsection>
<Subsection title="Disabled">
<Color.ColorPicker
size="small"
defaultValue="#ff0000"
disabled
/>
<Color.ColorPicker
size="medium"
defaultValue="#00ff00"
disabled
/>
<Color.ColorPicker
size="large"
defaultValue="#0000ff"
disabled
/>
</Subsection>
</Section>
</DefaultLayout>
)


+ 2
- 2
showcases/web-kitchensink-reactnext/src/pages/categories/option/index.tsx Voir le fichier

@@ -29,7 +29,7 @@ const OptionPage: NextPage<Props> = ({
<DefaultLayout
title="Option"
>
<main className="mt-8 mb-16 md:mt-16 md:mb-32">
<div className="mt-8 mb-16 md:mt-16 md:mb-32">
<section>
<div className="container mx-auto px-4">
<h1>
@@ -1655,7 +1655,7 @@ const OptionPage: NextPage<Props> = ({
</div>
</div>
</section>
</main>
</div>
</DefaultLayout>
);
};


+ 1
- 0
showcases/web-kitchensink-reactnext/src/styles/globals.css Voir le fichier

@@ -1,4 +1,5 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {


+ 35
- 2
showcases/web-kitchensink-reactnext/tailwind.config.js Voir le fichier

@@ -1,4 +1,24 @@
const defaultTheme = require('tailwindcss/defaultTheme')
const {
dropdownSelectPlugin,
menuSelectPlugin,
radioButtonPlugin,
radioTickBoxPlugin,
} = require('@tesseract-design/web-choice-react');
const {
colorPickerPlugin,
} = require('@tesseract-design/web-color-react');
const {
menuMultiSelectPlugin,
tagInputPlugin,
toggleButtonPlugin,
toggleSwitchPlugin,
toggleTickBoxPlugin,
} = require('@tesseract-design/web-multichoice-react');
const {
numberSpinnerPlugin,
sliderPlugin,
} = require('@tesseract-design/web-number-react');

/** @type {import('tailwindcss').Config} */
module.exports = {
@@ -6,7 +26,7 @@ module.exports = {
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/categories/**/*.{js,ts,jsx,tsx,mdx}',
'./node_modules/@tesseract-design/web-*-react/dist/**/*.js',
'./node_modules/@tesseract-design/web-*-react/dist/**/*.js', // catch-all, can use individual packages
],
theme: {
fontFamily: {
@@ -72,5 +92,18 @@ module.exports = {
},
},
},
plugins: [],
plugins: [
colorPickerPlugin,
dropdownSelectPlugin,
menuMultiSelectPlugin,
menuSelectPlugin,
numberSpinnerPlugin,
radioButtonPlugin,
radioTickBoxPlugin,
sliderPlugin,
tagInputPlugin,
toggleButtonPlugin,
toggleSwitchPlugin,
toggleTickBoxPlugin,
],
}

Chargement…
Annuler
Enregistrer