Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import StorybookDecorator from './storybook-decorator';

import '../src/tedi/styles/index.scss';
import '../src/community/styles/index.scss';
import '../node_modules/@tedi-design-system/core/icons/_all.scss';
import '../node_modules/@tedi-design-system/core/tedi-storybook-styles.scss';

import { PrintingProvider } from '../src/tedi/providers/printing-provider';
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
"import": "./community.es.js",
"require": "./community.cjs.js"
},
"./index.css": "./index.css"
"./index.css": "./index.css",
"./index-without-icons.css": "./index-without-icons.css",
"./icons/*.css": "./icons/*.css"
},
"scripts": {
"prepare": "husky",
"start": "storybook dev -p 4400 -c .storybook",
"build": "rm -rf dist && vite build --config vite.lib.config.ts && replace-in-file //fonts//g \"./fonts/\" dist/index.css --isRegex",
"build": "rm -rf dist && vite build --config vite.lib.config.ts && replace-in-file //fonts//g \"./fonts/\" dist/index.css dist/index-without-icons.css --isRegex",
"build:sb": "storybook build -c .storybook -o dist/storybook-static --stats-json && replace-in-file //fonts//g \"../fonts/\" \"dist/storybook-static/assets/*.css\" --isRegex",
"lint": "npx stylelint \"src/**/*.scss\" --fix && eslint \"src/**/*.{ts,tsx}\" --no-ignore --fix",
"lint:ci": "npx stylelint \"src/**/*.scss\" --quiet && npx eslint . --quiet",
Expand All @@ -47,7 +49,7 @@
"@mui/material": "^5.15.13",
"@mui/x-date-pickers": "^5.0.20",
"@tanstack/react-table": "^8.13.2",
"@tedi-design-system/core": "^6.9.0",
"@tedi-design-system/core": "6.11.2",
"classnames": "^2.5.1",
"draft-js": "^0.11.7",
"draftjs-md-converter": "^1.5.2",
Expand Down
9 changes: 8 additions & 1 deletion skills/tedi-react/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ function App() {
import '@tedi-design-system/react/index.css';
```

`index.css` declares all three Material Symbols fonts. When the app uses one `Icon` `type` (recommended), load only that font instead:

```tsx
import '@tedi-design-system/react/index-without-icons.css';
import '@tedi-design-system/react/icons/outlined.css'; // or rounded.css / sharp.css
```

Or in SCSS:
```scss
@use '@tedi-design-system/core/scss' as tedi;
Expand Down Expand Up @@ -278,7 +285,7 @@ sendNotification({ type: 'success', title: 'Done', children: 'Task completed' })

A handful of mistakes account for most TEDI integration issues. Avoid them up front:

- **Import from `/tedi` or `/community`, never the package root.** `@tedi-design-system/react` is not a valid import path — the package has explicit entry points (`@tedi-design-system/react/tedi`, `@tedi-design-system/react/community`, `@tedi-design-system/react/index.css`). Importing from the root will fail or silently miss types.
- **Import from `/tedi` or `/community`, never the package root.** `@tedi-design-system/react` is not a valid import path — the package has explicit entry points (`@tedi-design-system/react/tedi`, `@tedi-design-system/react/community`, `@tedi-design-system/react/index.css`, `@tedi-design-system/react/index-without-icons.css`, `@tedi-design-system/react/icons/*.css`). Importing from the root will fail or silently miss types.
- **Prefer TEDI-Ready over Community whenever possible.** Several Community components are deprecated in favor of TEDI-Ready equivalents, and the set with no TEDI-Ready alternative yet shifts over time — check the manifest's `status` field and the component JSDoc for the current deprecation status before reaching into Community. See [references/components.md](references/components.md).
- **Always pass `id` to form controls.** `TextField`, `Select`, `Checkbox`, `Radio`, etc. require it — it's how the label/helper/aria wiring works. There is no auto-generated fallback.
- **Use design tokens, not hardcoded colors.** Prefer the semantic roles (`var(--general-surface-primary)`, `var(--general-text-secondary)`) and drop to a `--tedi-*` primitive only when no semantic token fits. This is what makes theme switching and brand overrides work. Look names up in `node_modules/@tedi-design-system/core/tokens.json` rather than recalling them — see [references/theming.md](references/theming.md).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ $backgrounds: (
background: var(--general-surface-tertiary);
border-radius: var(--tedi-radius-02-default);

.filter-item__input:focus + & {
.filter-item__input:focus-visible + & {
@include mixins.focus-element;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
border: 1px solid var(--general-surface-disabled);
border-radius: var(--tedi-radius-02-default);

.light-item__input:focus + & {
.light-item__input:focus-visible + & {
@include mixins.focus-element;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
background-color: var(--general-surface-tertiary);
border: 1px solid var(--general-border-secondary);

.selector-item__input:focus + & {
.selector-item__input:focus-visible + & {
@include mixins.focus-element;

border-radius: 0;
Expand Down
6 changes: 5 additions & 1 deletion src/tedi/components/base/icon/icon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import { Icon, IconProps } from './icon';
* <a href="https://www.tedi.ee/1ee8444b7/p/28835d-icon" target="_blank">Zeroheight ↗</a><hr/>
* <a href="https://fonts.google.com/icons?icon.set=Material+Icons" target="_blank">Official Google Material Icons homepage icons ↗</a><br/>
* <a href="https://www.figma.com/community/file/1014241558898418245/material-design-icons?searchSessionId=lvxhc4l5-a6" target="_blank">Material Icons Figma ↗</a><br/>
* <a href="https://www.figma.com/community/plugin/740272380439725040/material-design-icons" target="_blank">Figma Material Symbols plugin ↗</a>
* <a href="https://www.figma.com/community/plugin/740272380439725040/material-design-icons" target="_blank">Figma Material Symbols plugin ↗</a><hr/>
*
* Use a single icon `type` throughout your application. Each type is a separate font file, so import
* `index-without-icons.css` together with only the style you use (e.g. `icons/outlined.css`) instead of
* `index.css`. See [Get started](/docs/documentation-get-started--get-started) for details and the PWA precache note.
*/
const meta: Meta<typeof Icon> = {
title: 'Tedi-Ready/Base/Icon',
Expand Down
3 changes: 2 additions & 1 deletion src/tedi/components/base/icon/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export interface IconSharedProps {
className?: string;
/**
* Type of icon
* It is recommended to only use one type throughout your app
* It is recommended to only use one type throughout your app, and to load only that type's font
* (`icons/<type>.css` with `index-without-icons.css`) instead of all three via `index.css`.
* @default outlined
*/
type?: IconType;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@use '@tedi-design-system/core/mixins';

.tedi-choice-group-item {
position: relative;

Expand All @@ -23,17 +21,6 @@
cursor: unset;
}

&__label {
box-sizing: border-box;
display: block;
width: 100%;
cursor: pointer;

.tedi-choice-group-item__input:focus + & {
@include mixins.focus-element;
}
}

&.tedi-choice-group-item--disabled {
background-color: var(--form-general-background-disabled);
border-color: var(--form-checkbox-radio-card-secondary-disabled-default-border);
Expand Down
40 changes: 40 additions & 0 deletions src/tedi/docs/getStarted.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,43 @@ currently not supported — if you need to, please reach out on Slack.
When using SSR you can pass the `defaultServerBreakpoint` prop to every component that uses
[BreakpointProps](/docs/helpers-usebreakpointprops--usebreakpointprops). This lets you declare which
breakpoint the component should render at on the server, avoiding layout shifts.

### Icon fonts

`Icon` renders [Material Symbols](https://fonts.google.com/icons) in three styles (`outlined`,
`rounded`, `sharp`), each a separate font file of roughly 350–430 KB. `index.css` declares all three,
so every style stays available. Use **one icon style** throughout your application and load only that
font:

```tsx
// Everything except the icon fonts…
import '@tedi-design-system/react/index-without-icons.css';
// …plus the one style you use (outlined is the Icon default).
import '@tedi-design-system/react/icons/outlined.css';
```

Each import loads one font file:

- `@tedi-design-system/react/icons/outlined.css`: `material-symbols-outlined.woff2`
- `@tedi-design-system/react/icons/rounded.css`: `material-symbols-rounded.woff2`
- `@tedi-design-system/react/icons/sharp.css`: `material-symbols-sharp.woff2`
- `@tedi-design-system/react/icons/all.css`: all three

An `Icon` whose `type` has no imported style renders its ligature text instead of the glyph.

Browsers only download an icon font once a glyph uses it, so in a regular web app the unused styles
cost nothing at runtime. In a **PWA**, the service worker precaches every matching build asset,
including fonts your CSS never references. Exclude the unused styles from the precache, for example
with `vite-plugin-pwa`:

```ts
VitePWA({
workbox: {
globPatterns: ['**/*.{js,css,html,woff2}'],
globIgnores: ['**/material-symbols-{rounded,sharp}.woff2'],
},
});
```

See the [core icons guide](https://github.com/TEDI-Design-System/core/blob/rc/docs/icons.md) for
SCSS usage and custom font paths.
4 changes: 3 additions & 1 deletion src/tedi/styles/index.scss
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
@use '@tedi-design-system/core/index';
// Icon fonts are not bundled here: the build appends them to index.css and ships per-style
// entries under icons/, so consumers can load a single Material Symbols style. See react#41.
@use '@tedi-design-system/core/index-without-icons';
27 changes: 26 additions & 1 deletion vite.lib.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable prettier/prettier */
import react from '@vitejs/plugin-react';
import { appendFileSync, copyFileSync, readFileSync } from 'fs';
import { resolve } from 'path';
import preserveDirectives from 'rollup-plugin-preserve-directives';
import { visualizer } from 'rollup-plugin-visualizer';
import { defineConfig, UserConfig } from 'vite';
import { defineConfig, Plugin, UserConfig } from 'vite';
import checker from 'vite-plugin-checker';
import dts from 'vite-plugin-dts';
import { viteStaticCopy } from 'vite-plugin-static-copy';
Expand All @@ -12,6 +13,25 @@ import packageJson from './package.json' with { type: 'json' };

const externalDependencies = [...Object.keys(packageJson.peerDependencies), 'react/jsx-runtime'];

const coreIconsDir = './node_modules/@tedi-design-system/core/icons';

/**
* The bundled CSS has no icon fonts (styles use core's index-without-icons). Keep index.css
* backward compatible by appending all three Material Symbols styles to it, and ship the
* icon-less bundle as index-without-icons.css so apps can pair it with one icons/<style>.css.
* Font URLs are written as /fonts/ to match the rest of the bundle; the build script rewrites them.
*/
const iconStylesheets = (): Plugin => ({
name: 'tedi-icon-stylesheets',
apply: 'build',
closeBundle() {
const indexCss = resolve(__dirname, 'dist/index.css');
copyFileSync(indexCss, resolve(__dirname, 'dist/index-without-icons.css'));
const allIcons = readFileSync(resolve(__dirname, coreIconsDir, 'all.css'), 'utf8');
appendFileSync(indexCss, allIcons.replace(/\.\.\/fonts\//g, '/fonts/'));
},
});

const config: UserConfig = {
define: {
'process.env.JEST_WORKER_ID': JSON.stringify(process.env.JEST_WORKER_ID),
Expand Down Expand Up @@ -47,8 +67,13 @@ const config: UserConfig = {
src: './node_modules/@tedi-design-system/core/fonts',
dest: './',
},
{
src: `${coreIconsDir}/*.css`,
dest: './icons',
},
],
}),
iconStylesheets(),
],
css: {
modules: {
Expand Down
Loading