Quellcode durchsuchen

Fix Lynx rendering

Properly specify input labels layout on Lynx.
master
TheoryOfNekomata vor 11 Monaten
Ursprung
Commit
6f00e7d138
52 geänderte Dateien mit 1152 neuen und 1090 gelöschten Zeilen
  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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

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


+ 5
- 6
categories/color/react/package.json Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

@@ -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 Datei anzeigen

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

@layer base {


+ 35
- 2
showcases/web-kitchensink-reactnext/tailwind.config.js Datei anzeigen

@@ -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,
],
}

Laden…
Abbrechen
Speichern