├── .nvmrc
├── .storybook
├── images
│ ├── .nojekyll
│ ├── googleda3b81df2a761821.html
│ ├── favicon.ico
│ ├── logo-ts.png
│ ├── sb-pkg-filter.png
│ └── master
│ │ └── index.html
├── docs
│ ├── SubcomponentsSection.md
│ └── DesignCompliantExampleSection.md
├── addons
│ └── version-switch
│ │ └── manager.ts
├── demoImages
│ ├── PC1.jpg
│ ├── PC2.jpg
│ ├── Person.png
│ ├── Laptop1.jpg
│ └── Laptop2.jpg
├── images-dev
│ └── favicon.ico
├── scoping.ts
├── components
│ ├── ArgTypesWithNote.module.css
│ ├── ControlsWithNote.module.css
│ ├── FilterBarExample.module.css
│ ├── LabelWithWrapping.tsx
│ ├── index.ts
│ ├── SplitterElementContent.tsx
│ ├── DomRefTable.module.css
│ ├── ProjectTemplate.module.css
│ ├── Footer.module.css
│ ├── GitHub-Mark.tsx
│ └── DocsHeader.module.css
└── tsconfig.json
├── packages
├── cli
│ ├── .gitignore
│ ├── tsconfig.build.json
│ ├── tsconfig.json
│ └── src
│ │ ├── scripts
│ │ ├── resolve-cem
│ │ │ └── main.ts
│ │ └── create-wrappers
│ │ │ ├── AbstractRenderer.ts
│ │ │ └── ExportsRenderer.ts
│ │ └── util
│ │ └── cem-reader.ts
├── cypress-commands
│ ├── .gitignore
│ ├── src
│ │ └── index.ts
│ ├── tsconfig.build.json
│ ├── tsconfig.json
│ ├── Queries.mdx
│ └── Commands.mdx
├── compat
│ ├── .gitignore
│ ├── src
│ │ ├── enums
│ │ │ ├── ToolbarStyle.ts
│ │ │ ├── LoaderType.ts
│ │ │ └── ToolbarDesign.ts
│ │ ├── components
│ │ │ ├── ToolbarSeparator
│ │ │ │ └── ToolbarSeparator.module.css
│ │ │ └── ToolbarSpacer
│ │ │ │ └── index.tsx
│ │ ├── internal
│ │ │ └── OverflowPopoverContext.ts
│ │ └── index.ts
│ ├── postcss.config.mjs
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── base
│ ├── .gitignore
│ ├── tsconfig.build.json
│ ├── src
│ │ ├── hooks
│ │ │ ├── index.ts
│ │ │ ├── useI18nBundle.ts
│ │ │ └── useViewportRange.ts
│ │ ├── internal
│ │ │ ├── hooks
│ │ │ │ ├── useIsomorphicLayoutEffect.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── useCurrentTheme.ts
│ │ │ ├── types
│ │ │ │ ├── Ui5CustomEvent.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── CommonProps.ts
│ │ │ └── utils
│ │ │ │ └── addCustomCSSWithScoping.ts
│ │ ├── types
│ │ │ └── index.ts
│ │ ├── Device
│ │ │ └── EventProvider.ts
│ │ └── index.ts
│ └── tsconfig.json
├── ai
│ ├── .gitignore
│ ├── tsconfig.build.json
│ ├── tsconfig.json
│ └── src
│ │ ├── components
│ │ └── PromptInput
│ │ │ └── PromptInput.stories.tsx
│ │ └── index.ts
├── charts
│ ├── .gitignore
│ ├── src
│ │ ├── internal
│ │ │ ├── defaults.ts
│ │ │ ├── staticProps.ts
│ │ │ └── ChartContainer.module.css
│ │ ├── components
│ │ │ ├── TimelineChart
│ │ │ │ └── util
│ │ │ │ │ ├── context.ts
│ │ │ │ │ └── error.ts
│ │ │ ├── PieChart
│ │ │ │ ├── PieChart.module.css
│ │ │ │ └── Placeholder.tsx
│ │ │ ├── ColumnChartWithTrend
│ │ │ │ ├── ColumnChartWithTrend.module.css
│ │ │ │ └── ColumnChartWithTrend.mdx
│ │ │ └── RadialChart
│ │ │ │ └── RadialChart.mdx
│ │ ├── interfaces
│ │ │ ├── index.ts
│ │ │ ├── IChartDimension.ts
│ │ │ └── IPolarChartConfig.ts
│ │ ├── hooks
│ │ │ ├── useChartMargin.ts
│ │ │ ├── useTooltipFormatter.ts
│ │ │ ├── useOnClickInternal.ts
│ │ │ ├── useLabelFormatter.ts
│ │ │ ├── useLegendItemClick.ts
│ │ │ └── useCancelAnimationFallback.ts
│ │ └── resources
│ │ │ └── NormalizedStackedChart.mdx
│ ├── tsconfig.json
│ ├── postcss.config.mjs
│ └── tsconfig.build.json
└── main
│ ├── src
│ ├── types
│ │ ├── CommonProps.ts
│ │ ├── Ui5DomRef.ts
│ │ ├── Ui5CustomEvent.ts
│ │ └── index.ts
│ ├── components
│ │ ├── VariantItem
│ │ │ └── VariantItem.module.css
│ │ ├── AnalyticalTable
│ │ │ ├── defaults
│ │ │ │ ├── Column
│ │ │ │ │ ├── RepeatedValue.tsx
│ │ │ │ │ └── Cell.tsx
│ │ │ │ └── NoDataComponent
│ │ │ │ │ └── index.tsx
│ │ │ ├── hooks
│ │ │ │ ├── useIsFirefox.ts
│ │ │ │ ├── useCanUseVoiceOver.ts
│ │ │ │ ├── useVisibleColumnsWidth.ts
│ │ │ │ ├── useResizeColumnsConfig.ts
│ │ │ │ └── useFontsReady.ts
│ │ │ ├── TableBody
│ │ │ │ └── EmptyRow.tsx
│ │ │ ├── pluginHooks
│ │ │ │ └── AnalyticalTableHooks.ts
│ │ │ └── TitleBar
│ │ │ │ └── index.tsx
│ │ ├── SplitterElement
│ │ │ └── SplitterElement.module.css
│ │ ├── VariantManagement
│ │ │ └── SaveViewDialog.module.css
│ │ ├── ObjectPageHeader
│ │ │ └── ObjectPageHeader.module.css
│ │ ├── ObjectPage
│ │ │ ├── context.ts
│ │ │ └── CollapsedAvatar.module.css
│ │ ├── FlexBox
│ │ │ └── FlexBox.mdx
│ │ ├── Grid
│ │ │ ├── Grid.mdx
│ │ │ └── Grid.module.css
│ │ ├── SplitterLayout
│ │ │ └── SplitterLayout.module.css
│ │ ├── MessageViewButton
│ │ │ └── MessageViewButton.mdx
│ │ ├── ThemeProvider
│ │ │ └── ThemeProvider.css
│ │ ├── ObjectPageTitle
│ │ │ └── ActionsSpacer.tsx
│ │ ├── ResponsiveGridLayout
│ │ │ └── ResponsiveGridLayout.mdx
│ │ └── NumericSideIndicator
│ │ │ └── NumericSideIndicator.module.css
│ ├── enums
│ │ ├── ContentDensity.ts
│ │ ├── Size.ts
│ │ ├── DeviationIndicator.ts
│ │ ├── GridPosition.ts
│ │ ├── VerticalAlign.ts
│ │ ├── TextAlign.ts
│ │ ├── MessageBoxType.ts
│ │ ├── MessageBoxAction.ts
│ │ ├── AnalyticalTableNoDataReason.ts
│ │ ├── Theme.ts
│ │ ├── ObjectPageMode.ts
│ │ ├── AnalyticalTableSelectionMode.ts
│ │ ├── FlexBoxWrap.ts
│ │ ├── ValueColor.ts
│ │ ├── AnalyticalTableSelectionBehavior.ts
│ │ ├── AnalyticalTablePopinDisplay.ts
│ │ ├── FlexBoxDirection.ts
│ │ ├── AnalyticalTableScrollMode.ts
│ │ ├── FlexBoxAlignItems.ts
│ │ └── FlexBoxJustifyContent.ts
│ ├── internal
│ │ ├── DynamicPageStickyHeader.css
│ │ ├── stopPropagation.ts
│ │ ├── withWebComponent.tsx
│ │ ├── SplitterLayoutContext.ts
│ │ ├── getRandomId.ts
│ │ ├── safeGetChildrenArray.ts
│ │ ├── MessageViewContext.ts
│ │ ├── ContainerQueries.ts
│ │ ├── OverflowPopoverContext.ts
│ │ └── VariantManagementContext.ts
│ ├── themes
│ │ ├── sap_belize_hcb.css
│ │ ├── sap_belize_hcw.css
│ │ ├── sap_fiori_3.css
│ │ ├── sap_fiori_3_dark.css
│ │ ├── sap_belize.css
│ │ ├── sap_fiori_3_hcb.css
│ │ └── sap_fiori_3_hcw.css
│ └── webComponents
│ │ ├── Switch
│ │ ├── Switch.stories.tsx
│ │ └── Switch.mdx
│ │ ├── ColorPicker
│ │ ├── ColorPicker.stories.tsx
│ │ └── ColorPicker.mdx
│ │ ├── Icon
│ │ └── Icon.mdx
│ │ ├── Link
│ │ ├── Link.mdx
│ │ └── Link.stories.tsx
│ │ ├── Text
│ │ └── Text.mdx
│ │ ├── Label
│ │ ├── Label.mdx
│ │ └── Label.stories.tsx
│ │ ├── Title
│ │ ├── Title.mdx
│ │ └── Title.stories.tsx
│ │ ├── RatingIndicator
│ │ ├── RatingIndicator.stories.tsx
│ │ └── RatingIndicator.mdx
│ │ ├── TextArea
│ │ ├── TextArea.mdx
│ │ └── TextArea.stories.tsx
│ │ ├── Slider
│ │ ├── Slider.stories.tsx
│ │ └── Slider.mdx
│ │ ├── Avatar
│ │ ├── Avatar.mdx
│ │ └── Avatar.stories.tsx
│ │ ├── DatePicker
│ │ └── DatePicker.mdx
│ │ ├── Carousel
│ │ └── Carousel.mdx
│ │ ├── Page
│ │ └── Page.mdx
│ │ ├── ToggleButton
│ │ ├── ToggleButton.mdx
│ │ └── ToggleButton.stories.tsx
│ │ ├── StepInput
│ │ ├── StepInput.mdx
│ │ └── StepInput.stories.tsx
│ │ ├── TimePicker
│ │ ├── TimePicker.mdx
│ │ └── TimePicker.stories.tsx
│ │ ├── AvatarGroup
│ │ └── AvatarGroup.mdx
│ │ ├── ExpandableText
│ │ └── ExpandableText.mdx
│ │ ├── RangeSlider
│ │ ├── RangeSlider.mdx
│ │ └── RangeSlider.stories.tsx
│ │ ├── SplitButton
│ │ ├── SplitButton.mdx
│ │ └── SplitButton.stories.tsx
│ │ ├── DateTimePicker
│ │ └── DateTimePicker.mdx
│ │ ├── DateRangePicker
│ │ └── DateRangePicker.mdx
│ │ ├── DynamicSideContent
│ │ └── DynamicSideContent.mdx
│ │ ├── ProgressIndicator
│ │ ├── ProgressIndicator.mdx
│ │ └── ProgressIndicator.stories.tsx
│ │ ├── BarcodeScannerDialog
│ │ └── BarcodeScannerDialog.mdx
│ │ ├── Tag
│ │ └── Tag.mdx
│ │ ├── Panel
│ │ └── Panel.mdx
│ │ ├── CheckBox
│ │ └── CheckBox.mdx
│ │ ├── MessageStrip
│ │ ├── MessageStrip.mdx
│ │ └── MessageStrip.stories.tsx
│ │ ├── Bar
│ │ └── Bar.mdx
│ │ ├── BusyIndicator
│ │ └── BusyIndicator.mdx
│ │ ├── FileUploader
│ │ └── FileUploader.mdx
│ │ ├── FlexibleColumnLayout
│ │ └── FlexibleColumnLayout.mdx
│ │ ├── RadioButton
│ │ └── RadioButton.mdx
│ │ ├── ProductSwitch
│ │ └── ProductSwitch.mdx
│ │ ├── SegmentedButton
│ │ └── SegmentedButton.stories.tsx
│ │ ├── IllustratedMessage
│ │ └── IllustratedMessage.stories.tsx
│ │ ├── Breadcrumbs
│ │ └── Breadcrumbs.mdx
│ │ └── Dialog
│ │ └── Dialog.mdx
│ ├── tsconfig.build.json
│ ├── .gitignore
│ ├── postcss.config.mjs
│ ├── tsconfig.json
│ ├── README.md
│ └── scripts
│ └── create-enum-export.mjs
├── .husky
└── pre-commit
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ └── config.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── open-source-security.yml
├── examples
├── vite-ts
│ ├── src
│ │ ├── vite-env.d.ts
│ │ ├── AppShell.module.css
│ │ ├── ToDos.module.css
│ │ ├── index.css
│ │ ├── TodoDetails.module.css
│ │ ├── App.cy.tsx
│ │ └── mockImplementations
│ │ │ └── mockAPIs.ts
│ ├── public
│ │ └── person.png
│ ├── cypress
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── e2e
│ │ │ └── App.cy.tsx
│ │ └── support
│ │ │ ├── component-index.html
│ │ │ └── e2e.ts
│ ├── vite.config.ts
│ ├── tsconfig.spec.json
│ ├── tsconfig.node.json
│ ├── .gitignore
│ ├── cypress.config.ts
│ ├── index.html
│ ├── tsconfig.json
│ └── eslint.config.mjs
├── nextjs-pages
│ ├── pages
│ │ ├── index.module.css
│ │ ├── api
│ │ │ └── todos
│ │ │ │ └── [id].ts
│ │ └── _app.tsx
│ ├── next.config.js
│ ├── styles
│ │ └── globals.css
│ ├── components
│ │ └── AppShell
│ │ │ └── AppShell.module.css
│ ├── eslint.config.mjs
│ ├── .gitignore
│ ├── tsconfig.json
│ └── package.json
├── react-router-ts
│ ├── .gitignore
│ ├── app
│ │ ├── components
│ │ │ ├── AppShellBar.module.css
│ │ │ └── AppShell.tsx
│ │ ├── routes.ts
│ │ └── globals.css
│ ├── public
│ │ └── favicon.ico
│ ├── react-router.config.ts
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── README.md
├── nextjs-app
│ ├── app
│ │ ├── components
│ │ │ ├── AppShellBar.module.css
│ │ │ └── AppShell.tsx
│ │ ├── favicon.ico
│ │ ├── loading.module.css
│ │ ├── loading.tsx
│ │ ├── globals.css
│ │ ├── page.tsx
│ │ └── layout.tsx
│ ├── next.config.js
│ ├── eslint.config.mjs
│ ├── .gitignore
│ ├── package.json
│ └── tsconfig.json
└── remix-ts
│ └── README.md
├── templates
├── vite-ts
│ ├── src
│ │ ├── vite-env.d.ts
│ │ ├── index.css
│ │ ├── App.cy.tsx
│ │ ├── main.tsx
│ │ └── App.tsx
│ ├── cypress
│ │ ├── fixtures
│ │ │ └── example.json
│ │ └── support
│ │ │ └── component-index.html
│ ├── vite.config.ts
│ ├── cypress.config.ts
│ ├── tsconfig.spec.json
│ ├── tsconfig.node.json
│ ├── .gitignore
│ ├── index.html
│ ├── tsconfig.json
│ ├── eslint.config.mjs
│ └── README.md
├── nextjs-app
│ ├── app
│ │ ├── clientAssetsImport.ts
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── page.tsx
│ │ └── layout.tsx
│ ├── next.config.js
│ ├── eslint.config.mjs
│ ├── .gitignore
│ ├── package.json
│ └── tsconfig.json
└── nextjs-pages
│ ├── next.config.js
│ ├── styles
│ └── globals.css
│ ├── eslint.config.mjs
│ ├── .gitignore
│ ├── pages
│ ├── index.tsx
│ └── _app.tsx
│ ├── tsconfig.json
│ └── package.json
├── patterns
├── navigation-layout
│ ├── src
│ │ ├── vite-env.d.ts
│ │ ├── assets
│ │ │ └── avatar.png
│ │ ├── main.tsx
│ │ └── ClearAllMessageBox.tsx
│ ├── vite.config.ts
│ ├── tsconfig.node.json
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── tsconfig.json
│ ├── eslint.config.mjs
│ └── package.json
├── Docs.mdx
└── selection-assistant
│ └── SelectionAssistantContainer.tsx
├── .yarnrc.yml
├── assets
├── Logo.png
├── Logo-Sticker.png
└── SAP_Best_R_grad_blk_scrn.png
├── makefile
├── .prettierignore
├── docs
├── styling
│ ├── CssPartsExample.css
│ ├── MyCustomElement.css
│ ├── MyCustomElement.tsx
│ └── CssPartsExample.tsx
├── ReadMeAI.mdx
├── Changelog.mdx
├── ReadMeCompat.mdx
├── MigrationGuide.css
├── knowledgeBaseExamples
│ └── slotExamples.tsx
├── EmbeddedStackBlitz.tsx
└── knowledge-base
│ └── SsrLimitations.tsx
├── tsconfig.node.json
├── config
├── .gitmessage
├── layers-plugin.js
└── paths.js
├── cypress
└── support
│ ├── component.tsx
│ └── component-index.html
├── nx.json
├── .browserslistrc
├── tsconfig.spec.json
├── types.d.ts
├── .editorconfig
├── prettier.config.js
├── lerna.json
├── tsconfig.build.json
├── translation_v2.json
├── .gitignore
├── .pipeline
└── config.yml
└── tsconfig.json
/.nvmrc:
--------------------------------------------------------------------------------
1 | 24.12.0
2 |
--------------------------------------------------------------------------------
/.storybook/images/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/cli/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | test
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | yarn run lint-staged
2 |
--------------------------------------------------------------------------------
/packages/cypress-commands/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/packages/compat/.gitignore:
--------------------------------------------------------------------------------
1 | /dist
2 | src/**/*.css.ts
--------------------------------------------------------------------------------
/packages/base/.gitignore:
--------------------------------------------------------------------------------
1 | /LICENSE
2 | /NOTICE.txt
3 | /dist
4 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # general code owners
2 | * @MarcusNotheis @Lukas742
3 |
--------------------------------------------------------------------------------
/examples/vite-ts/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/templates/vite-ts/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/packages/ai/.gitignore:
--------------------------------------------------------------------------------
1 | /LICENSE
2 | /NOTICE.txt
3 | /dist
4 |
5 | src/**/*.css.ts
--------------------------------------------------------------------------------
/packages/cli/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json"
3 | }
4 |
--------------------------------------------------------------------------------
/.storybook/docs/SubcomponentsSection.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Subcomponents
5 |
--------------------------------------------------------------------------------
/packages/charts/.gitignore:
--------------------------------------------------------------------------------
1 | /LICENSE
2 | /NOTICE.txt
3 | /dist
4 |
5 | src/**/*.css.ts
--------------------------------------------------------------------------------
/patterns/navigation-layout/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/.storybook/addons/version-switch/manager.ts:
--------------------------------------------------------------------------------
1 | import '../../components/VersionSwitch.js';
2 |
--------------------------------------------------------------------------------
/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
3 | yarnPath: .yarn/releases/yarn-4.12.0.cjs
4 |
--------------------------------------------------------------------------------
/assets/Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/assets/Logo.png
--------------------------------------------------------------------------------
/examples/nextjs-pages/pages/index.module.css:
--------------------------------------------------------------------------------
1 | .pageHeader {
2 | padding-inline: 0;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/cypress-commands/src/index.ts:
--------------------------------------------------------------------------------
1 | import './commands.js';
2 | import './queries.js';
3 |
--------------------------------------------------------------------------------
/.storybook/images/googleda3b81df2a761821.html:
--------------------------------------------------------------------------------
1 | google-site-verification: googleda3b81df2a761821.html
2 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | chromatic:
2 | git commit --allow-empty --message "[ci chromatic]"
3 | git push origin
4 |
--------------------------------------------------------------------------------
/assets/Logo-Sticker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/assets/Logo-Sticker.png
--------------------------------------------------------------------------------
/examples/react-router-ts/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /.cache
4 | /build
5 | .env
6 | .react-router/
7 |
--------------------------------------------------------------------------------
/packages/main/src/types/CommonProps.ts:
--------------------------------------------------------------------------------
1 | export type { CommonProps } from '@ui5/webcomponents-react-base';
2 |
--------------------------------------------------------------------------------
/packages/main/src/types/Ui5DomRef.ts:
--------------------------------------------------------------------------------
1 | export type { Ui5DomRef } from '@ui5/webcomponents-react-base';
2 |
--------------------------------------------------------------------------------
/.storybook/demoImages/PC1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/demoImages/PC1.jpg
--------------------------------------------------------------------------------
/.storybook/demoImages/PC2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/demoImages/PC2.jpg
--------------------------------------------------------------------------------
/.storybook/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/images/favicon.ico
--------------------------------------------------------------------------------
/.storybook/images/logo-ts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/images/logo-ts.png
--------------------------------------------------------------------------------
/packages/main/src/types/Ui5CustomEvent.ts:
--------------------------------------------------------------------------------
1 | export type { Ui5CustomEvent } from '@ui5/webcomponents-react-base';
2 |
--------------------------------------------------------------------------------
/.storybook/demoImages/Person.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/demoImages/Person.png
--------------------------------------------------------------------------------
/templates/nextjs-app/app/clientAssetsImport.ts:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import '@ui5/webcomponents-react/dist/Assets';
4 |
--------------------------------------------------------------------------------
/.storybook/demoImages/Laptop1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/demoImages/Laptop1.jpg
--------------------------------------------------------------------------------
/.storybook/demoImages/Laptop2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/demoImages/Laptop2.jpg
--------------------------------------------------------------------------------
/.storybook/images-dev/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/images-dev/favicon.ico
--------------------------------------------------------------------------------
/examples/vite-ts/public/person.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/examples/vite-ts/public/person.png
--------------------------------------------------------------------------------
/packages/main/src/components/VariantItem/VariantItem.module.css:
--------------------------------------------------------------------------------
1 | .variantItem::part(title) {
2 | text-align: start;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/main/src/enums/ContentDensity.ts:
--------------------------------------------------------------------------------
1 | export enum ContentDensity {
2 | Cozy = 'Cozy',
3 | Compact = 'Compact',
4 | }
5 |
--------------------------------------------------------------------------------
/.storybook/images/sb-pkg-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/.storybook/images/sb-pkg-filter.png
--------------------------------------------------------------------------------
/assets/SAP_Best_R_grad_blk_scrn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/assets/SAP_Best_R_grad_blk_scrn.png
--------------------------------------------------------------------------------
/examples/nextjs-app/app/components/AppShellBar.module.css:
--------------------------------------------------------------------------------
1 | .popover {
2 | }
3 | .popover::part(content) {
4 | padding: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/examples/nextjs-app/app/favicon.ico
--------------------------------------------------------------------------------
/packages/compat/src/enums/ToolbarStyle.ts:
--------------------------------------------------------------------------------
1 | export enum ToolbarStyle {
2 | Clear = 'Clear',
3 | Standard = 'Standard',
4 | }
5 |
--------------------------------------------------------------------------------
/packages/main/src/enums/Size.ts:
--------------------------------------------------------------------------------
1 | export enum Size {
2 | Small = 'Small',
3 | Medium = 'Medium',
4 | Large = 'Large',
5 | }
6 |
--------------------------------------------------------------------------------
/templates/nextjs-app/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/templates/nextjs-app/app/favicon.ico
--------------------------------------------------------------------------------
/examples/react-router-ts/app/components/AppShellBar.module.css:
--------------------------------------------------------------------------------
1 | .popover {
2 | }
3 | .popover::part(content) {
4 | padding: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/charts/src/internal/defaults.ts:
--------------------------------------------------------------------------------
1 | export const defaultFormatter = (d) => d;
2 |
3 | export const defaultMaxYAxisWidth = 200;
4 |
--------------------------------------------------------------------------------
/packages/main/src/internal/DynamicPageStickyHeader.css:
--------------------------------------------------------------------------------
1 | .dynamicPageStickyContent::part(fit-content) {
2 | position: static;
3 | }
4 |
--------------------------------------------------------------------------------
/examples/nextjs-app/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | module.exports = nextConfig;
5 |
--------------------------------------------------------------------------------
/examples/react-router-ts/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/examples/react-router-ts/public/favicon.ico
--------------------------------------------------------------------------------
/packages/base/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "**/*.cy.ts", "**/*.cy.tsx"]
4 | }
5 |
--------------------------------------------------------------------------------
/packages/compat/src/enums/LoaderType.ts:
--------------------------------------------------------------------------------
1 | export enum LoaderType {
2 | Determinate = 'Determinate',
3 | Indeterminate = 'Indeterminate',
4 | }
5 |
--------------------------------------------------------------------------------
/packages/cypress-commands/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "include": ["src"],
4 | "exclude": ["test"]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/main/src/enums/DeviationIndicator.ts:
--------------------------------------------------------------------------------
1 | export enum DeviationIndicator {
2 | Down = 'Down',
3 | Up = 'Up',
4 | None = 'None',
5 | }
6 |
--------------------------------------------------------------------------------
/packages/main/src/enums/GridPosition.ts:
--------------------------------------------------------------------------------
1 | export enum GridPosition {
2 | Left = 'Left',
3 | Center = 'Center',
4 | Right = 'Right',
5 | }
6 |
--------------------------------------------------------------------------------
/templates/nextjs-app/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {};
3 |
4 | module.exports = nextConfig;
5 |
--------------------------------------------------------------------------------
/examples/vite-ts/src/AppShell.module.css:
--------------------------------------------------------------------------------
1 | .popover::part(content) {
2 | padding: 0;
3 | }
4 |
5 | .dynamicPage {
6 | height: calc(100% - 52px);
7 | }
8 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/src/assets/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UI5/webcomponents-react/HEAD/patterns/navigation-layout/src/assets/avatar.png
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | *.module.css.ts
2 | *.css.ts
3 |
4 | yarn.lock
5 | .next
6 | dist
7 | temp
8 | .out
9 |
10 | .nx
11 | /.nx/cache
12 | /.nx/workspace-data
--------------------------------------------------------------------------------
/examples/vite-ts/src/ToDos.module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | box-sizing: border-box;
3 | }
4 |
5 | .list {
6 | box-sizing: border-box;
7 | padding: 0.5rem;
8 | }
9 |
--------------------------------------------------------------------------------
/packages/main/src/internal/stopPropagation.ts:
--------------------------------------------------------------------------------
1 | export const stopPropagation = (e) => {
2 | e.stopPropagation();
3 | e.stopImmediatePropagation?.();
4 | };
5 |
--------------------------------------------------------------------------------
/docs/styling/CssPartsExample.css:
--------------------------------------------------------------------------------
1 | .card::part(root) {
2 | background-color: lightgreen;
3 | }
4 | .card::part(content) {
5 | transform: rotate(180deg);
6 | }
7 |
--------------------------------------------------------------------------------
/packages/main/src/enums/VerticalAlign.ts:
--------------------------------------------------------------------------------
1 | export enum VerticalAlign {
2 | Bottom = 'Bottom',
3 | Inherit = 'Inherit',
4 | Middle = 'Middle',
5 | Top = 'Top',
6 | }
7 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/loading.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 100%;
3 | height: 100%;
4 | display: flex;
5 | align-items: center;
6 | justify-content: center;
7 | }
8 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | };
5 |
6 | module.exports = nextConfig;
7 |
--------------------------------------------------------------------------------
/packages/compat/src/enums/ToolbarDesign.ts:
--------------------------------------------------------------------------------
1 | export enum ToolbarDesign {
2 | Auto = 'Auto',
3 | Info = 'Info',
4 | Solid = 'Solid',
5 | Transparent = 'Transparent',
6 | }
7 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | };
5 |
6 | module.exports = nextConfig;
7 |
--------------------------------------------------------------------------------
/packages/charts/src/components/TimelineChart/util/context.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | export const TimelineChartBodyCtx = createContext({ chartBodyWidth: 0 });
4 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/defaults/Column/RepeatedValue.tsx:
--------------------------------------------------------------------------------
1 | export const RepeatedValue = () => null;
2 |
3 | RepeatedValue.displayName = 'RepeatedValueCellContent';
4 |
--------------------------------------------------------------------------------
/templates/vite-ts/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | width: 100vw;
4 | height: 100vh;
5 | background: var(--sapBackgroundColor);
6 | font-family: var(--sapFontFamily);
7 | }
8 |
--------------------------------------------------------------------------------
/packages/base/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | import { useI18nBundle } from './useI18nBundle.js';
2 | import { useViewportRange } from './useViewportRange.js';
3 |
4 | export { useI18nBundle, useViewportRange };
5 |
--------------------------------------------------------------------------------
/packages/main/src/internal/withWebComponent.tsx:
--------------------------------------------------------------------------------
1 | export { withWebComponent } from '@ui5/webcomponents-react-base';
2 | export type { WithWebComponentPropTypes } from '@ui5/webcomponents-react-base';
3 |
--------------------------------------------------------------------------------
/.storybook/scoping.ts:
--------------------------------------------------------------------------------
1 | import { setCompatCustomElementsScopingSuffix } from '@ui5/webcomponents-compat/dist/utils/CompatCustomElementsScope.js';
2 |
3 | setCompatCustomElementsScopingSuffix('compat');
4 |
--------------------------------------------------------------------------------
/examples/vite-ts/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | width: 100vw;
4 | height: 100vh;
5 | background: var(--sapBackgroundColor);
6 | }
7 |
8 | #root {
9 | height: 100%;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/main/src/enums/TextAlign.ts:
--------------------------------------------------------------------------------
1 | export enum TextAlign {
2 | Begin = 'Begin',
3 | End = 'End',
4 | Left = 'Left',
5 | Right = 'Right',
6 | Center = 'Center',
7 | Initial = 'Initial',
8 | }
9 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/styles/globals.css:
--------------------------------------------------------------------------------
1 | :not(:defined) {
2 | display: none;
3 | }
4 |
5 | html,
6 | body {
7 | max-width: 100vw;
8 | overflow-x: hidden;
9 | padding: 0;
10 | margin: 0;
11 | }
12 |
--------------------------------------------------------------------------------
/examples/vite-ts/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/main/src/enums/MessageBoxType.ts:
--------------------------------------------------------------------------------
1 | export enum MessageBoxType {
2 | Confirm = 'Confirm',
3 | Error = 'Error',
4 | Information = 'Information',
5 | Success = 'Success',
6 | Warning = 'Warning',
7 | }
8 |
--------------------------------------------------------------------------------
/templates/vite-ts/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/.storybook/components/ArgTypesWithNote.module.css:
--------------------------------------------------------------------------------
1 | .tableContainer {
2 | margin-top: 25px;
3 |
4 | table {
5 | margin-top: 0 !important;
6 | }
7 | }
8 |
9 | .strip {
10 | margin-bottom: 10px;
11 | }
12 |
--------------------------------------------------------------------------------
/examples/vite-ts/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import react from '@vitejs/plugin-react';
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | });
8 |
--------------------------------------------------------------------------------
/packages/compat/src/components/ToolbarSeparator/ToolbarSeparator.module.css:
--------------------------------------------------------------------------------
1 | .separator {
2 | width: 0.0625rem;
3 | height: var(--_ui5wcr-ToolbarSeparatorHeight);
4 | background: var(--sapToolbar_SeparatorColor);
5 | }
6 |
--------------------------------------------------------------------------------
/templates/vite-ts/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import react from '@vitejs/plugin-react';
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | });
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Questions
4 | url: https://github.com/UI5/webcomponents-react/discussions
5 | about: Please ask and answer questions here.
6 |
--------------------------------------------------------------------------------
/packages/main/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export type {
2 | ReducedReactNode,
3 | ReducedReactNodeWithBoolean,
4 | UI5WCSlotsNode,
5 | CommonProps,
6 | Ui5CustomEvent,
7 | Ui5DomRef,
8 | } from '@ui5/webcomponents-react-base';
9 |
--------------------------------------------------------------------------------
/examples/react-router-ts/app/routes.ts:
--------------------------------------------------------------------------------
1 | import { index, route, type RouteConfig } from '@react-router/dev/routes';
2 |
3 | export default [index('./routes/index.tsx'), route('todos/:id', './routes/todo.tsx')] satisfies RouteConfig;
4 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/vite.config.ts:
--------------------------------------------------------------------------------
1 | import react from '@vitejs/plugin-react';
2 | import { defineConfig } from 'vite';
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | });
8 |
--------------------------------------------------------------------------------
/packages/base/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "noImplicitAny": false,
6 | "strictNullChecks": false
7 | },
8 | "include": ["src"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/main/src/components/SplitterElement/SplitterElement.module.css:
--------------------------------------------------------------------------------
1 | .splitterElement {
2 | display: flex;
3 | overflow: hidden;
4 | position: relative;
5 | will-change: flex-basis;
6 | min-width: 0px;
7 | min-height: 0px;
8 | }
9 |
--------------------------------------------------------------------------------
/templates/vite-ts/src/App.cy.tsx:
--------------------------------------------------------------------------------
1 | import App from './App';
2 |
3 | describe('Component tests', () => {
4 | it('basic component test', () => {
5 | cy.mount( );
6 | cy.get('[ui5-shellbar]').should('be.visible');
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/.storybook/components/ControlsWithNote.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | margin-block-start: 25px !important;
3 | }
4 |
5 | .container:has(> .strip) table {
6 | margin-top: 0px;
7 | }
8 |
9 | .strip {
10 | margin-block-end: 10px;
11 | }
12 |
--------------------------------------------------------------------------------
/examples/remix-ts/README.md:
--------------------------------------------------------------------------------
1 | # UI5 Web Components React - Remix Example
2 |
3 | This example got updated to use React Router v7.
4 | You can find the new example [here](https://github.com/UI5/webcomponents-react/tree/main/examples/react-router-ts).
5 |
--------------------------------------------------------------------------------
/packages/base/src/internal/hooks/useIsomorphicLayoutEffect.ts:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect, useLayoutEffect } from 'react';
4 |
5 | export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
6 |
--------------------------------------------------------------------------------
/examples/vite-ts/src/TodoDetails.module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | margin-block-start: 1rem;
3 | box-sizing: border-box;
4 | }
5 |
6 | .form {
7 | padding: 1rem;
8 | }
9 |
10 | .formControl {
11 | width: 100%;
12 | max-width: 45rem;
13 | }
14 |
--------------------------------------------------------------------------------
/templates/vite-ts/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress';
2 |
3 | export default defineConfig({
4 | component: {
5 | devServer: {
6 | framework: 'react',
7 | bundler: 'vite',
8 | },
9 | },
10 | });
11 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "compilerOptions": {
4 | "composite": true,
5 | "allowJs": true
6 | },
7 | "include": ["scripts", "config", ".github"],
8 | "files": ["prettier.config.js"]
9 | }
10 |
--------------------------------------------------------------------------------
/docs/styling/MyCustomElement.css:
--------------------------------------------------------------------------------
1 | .containerCustomElement {
2 | background-color: var(--sapBackgroundColor);
3 | font-family: var(--sapFontFamily);
4 | height: 50px;
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
--------------------------------------------------------------------------------
/.storybook/images/master/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages/ai/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "references": [
4 | {
5 | "path": "../base/tsconfig.build.json"
6 | }
7 | ],
8 | "exclude": ["node_modules", "**/*.cy.ts", "**/*.cy.tsx", "**/*.stories.tsx"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/main/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "references": [
4 | {
5 | "path": "../base/tsconfig.build.json"
6 | }
7 | ],
8 | "exclude": ["node_modules", "**/*.cy.ts", "**/*.cy.tsx", "**/*.stories.tsx"]
9 | }
10 |
--------------------------------------------------------------------------------
/.storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./../tsconfig.base.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "allowImportingTsExtensions": true
6 | },
7 | "include": ["./**/*.js", "./**/*.tsx", "./**/*.ts", "../patterns/selection-assistant"]
8 | }
9 |
--------------------------------------------------------------------------------
/examples/vite-ts/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "es5",
5 | "lib": ["es5", "dom"],
6 | "types": ["cypress", "node"],
7 | "jsx": "react-jsx"
8 | },
9 | "include": ["cypress", "src"]
10 | }
11 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/styles/globals.css:
--------------------------------------------------------------------------------
1 | :not(:defined) {
2 | display: none;
3 | }
4 |
5 | html,
6 | body {
7 | margin: 0;
8 | width: 100vw;
9 | height: 100vh;
10 | background: var(--sapBackgroundColor);
11 | font-family: var(--sapFontFamily);
12 | }
13 |
--------------------------------------------------------------------------------
/templates/vite-ts/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "es5",
5 | "lib": ["es5", "dom"],
6 | "types": ["cypress", "node"],
7 | "jsx": "react-jsx"
8 | },
9 | "include": ["cypress", "src"]
10 | }
11 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/components/AppShell/AppShell.module.css:
--------------------------------------------------------------------------------
1 | .appShell {
2 | height: 100vh;
3 | width: 100vw;
4 | overflow: hidden;
5 | }
6 |
7 | .scrollContainer {
8 | height: calc(100vh - 3.25rem);
9 | overflow-y: auto;
10 | position: relative;
11 | }
12 |
--------------------------------------------------------------------------------
/examples/react-router-ts/react-router.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from '@react-router/dev/config';
2 |
3 | export default {
4 | // Config options...
5 | // Server-side render by default, to enable SPA mode set this to `false`
6 | ssr: true,
7 | } satisfies Config;
8 |
--------------------------------------------------------------------------------
/packages/charts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "references": [
4 | {
5 | "path": "../base/tsconfig.json"
6 | },
7 | {
8 | "path": "../main/tsconfig.json"
9 | }
10 | ],
11 | "include": ["src"]
12 | }
13 |
--------------------------------------------------------------------------------
/packages/main/.gitignore:
--------------------------------------------------------------------------------
1 | /components
2 | /enums
3 | /internal
4 | /webComponents
5 | /index.d.ts
6 | /index.esm.js
7 | /LICENSE
8 | /NOTICE.txt
9 | /scripts/wrapperGeneration/dist
10 | /dist
11 | /wrappers
12 | /ssr
13 | src/i18n/i18n-defaults.ts
14 | src/**/*.css.ts
15 |
--------------------------------------------------------------------------------
/config/.gitmessage:
--------------------------------------------------------------------------------
1 | # type is one of fix, feat, chore, docs, style, refactor, perf, test
2 | [optional scope]:
3 |
4 | # [Optional] Body, Indicate a Breaking Change here by starting with BREAKING CHANGE
5 |
6 | # [Optional] Footer, you can reference issues here
7 |
--------------------------------------------------------------------------------
/examples/react-router-ts/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { reactRouter } from '@react-router/dev/vite';
2 | import { defineConfig } from 'vite';
3 | import tsconfigPaths from 'vite-tsconfig-paths';
4 |
5 | export default defineConfig({
6 | plugins: [reactRouter(), tsconfigPaths()],
7 | });
8 |
--------------------------------------------------------------------------------
/cypress/support/component.tsx:
--------------------------------------------------------------------------------
1 | import 'cypress-real-events';
2 | import '@cypress/code-coverage/support';
3 | import '@testing-library/cypress/add-commands';
4 | import './commands';
5 | import '../../packages/cypress-commands/src/index.js';
6 | import '../../packages/main/dist/Assets.js';
7 |
--------------------------------------------------------------------------------
/packages/main/src/enums/MessageBoxAction.ts:
--------------------------------------------------------------------------------
1 | export enum MessageBoxAction {
2 | Abort = 'Abort',
3 | Cancel = 'Cancel',
4 | Close = 'Close',
5 | Delete = 'Delete',
6 | Ignore = 'Ignore',
7 | No = 'No',
8 | OK = 'OK',
9 | Retry = 'Retry',
10 | Yes = 'Yes',
11 | }
12 |
--------------------------------------------------------------------------------
/packages/charts/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs';
2 | import { postcssConfigFactory } from '../../config/postcss-config-factory.js';
3 |
4 | const packageName = JSON.parse(fs.readFileSync('./package.json').toString()).name;
5 |
6 | export default postcssConfigFactory(packageName);
7 |
--------------------------------------------------------------------------------
/packages/compat/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs';
2 | import { postcssConfigFactory } from '../../config/postcss-config-factory.js';
3 |
4 | const packageName = JSON.parse(fs.readFileSync('./package.json').toString()).name;
5 |
6 | export default postcssConfigFactory(packageName);
7 |
--------------------------------------------------------------------------------
/packages/main/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs';
2 | import { postcssConfigFactory } from '../../config/postcss-config-factory.js';
3 |
4 | const packageName = JSON.parse(fs.readFileSync('./package.json').toString()).name;
5 |
6 | export default postcssConfigFactory(packageName);
7 |
--------------------------------------------------------------------------------
/.storybook/components/FilterBarExample.module.css:
--------------------------------------------------------------------------------
1 | .filterBarDemo {
2 | padding: 1rem;
3 | border: var(--sapElement_BorderWidth) solid var(--sapNeutralBorderColor);
4 | border-radius: var(--sapElement_BorderCornerRadius);
5 | }
6 |
7 | .filterBarDemo [ui5-dialog] {
8 | max-height: 80vh;
9 | }
10 |
--------------------------------------------------------------------------------
/.storybook/docs/DesignCompliantExampleSection.md:
--------------------------------------------------------------------------------
1 | ## Design-Compliant Examples
2 |
3 | These examples demonstrate the implementation of design specifications. They primarily illustrate design concepts and mostly do not provide additional functionality. You can reference them to select the appropriate design patterns.
4 |
--------------------------------------------------------------------------------
/examples/vite-ts/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts", "cypress.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/templates/vite-ts/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts", "cypress.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts", "cypress.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/main/src/components/VariantManagement/SaveViewDialog.module.css:
--------------------------------------------------------------------------------
1 | .dialog {
2 | &::part(footer) {
3 | border-block-start: none;
4 | padding: 0;
5 | }
6 | }
7 |
8 | .input {
9 | width: 100%;
10 | margin-block: 0.1875rem;
11 | }
12 |
13 | .checkBoxesContainer {
14 | padding-inline: 0.5rem;
15 | }
16 |
--------------------------------------------------------------------------------
/packages/main/src/internal/SplitterLayoutContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | interface ISplitterLayoutContext {
4 | vertical: boolean;
5 | reset: boolean;
6 | }
7 |
8 | export const SplitterLayoutContext = createContext({
9 | vertical: true,
10 | reset: false,
11 | });
12 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_belize_hcb.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_belize_hcb'] {
2 | --_ui5wcr_Scrollbar_Border: 0.0625rem solid #999;
3 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
4 | --_ui5wcr_Scrollbar_BorderRadius: 0;
5 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
6 | }
7 |
--------------------------------------------------------------------------------
/nx.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/nx/schemas/nx-schema.json",
3 | "namedInputs": {
4 | "default": ["{projectRoot}/**/*", "sharedGlobals"],
5 | "sharedGlobals": [],
6 | "production": ["default"]
7 | },
8 | "targetDefaults": {
9 | "clean": {
10 | "dependsOn": ["^clean"]
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/charts/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "references": [
4 | {
5 | "path": "../base/tsconfig.build.json"
6 | },
7 | {
8 | "path": "../main/tsconfig.build.json"
9 | }
10 | ],
11 | "exclude": ["node_modules", "**/*.cy.ts", "**/*.cy.tsx", "**/*.stories.tsx"]
12 | }
13 |
--------------------------------------------------------------------------------
/packages/compat/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "references": [
4 | {
5 | "path": "../base/tsconfig.build.json"
6 | },
7 | {
8 | "path": "../main/tsconfig.build.json"
9 | }
10 | ],
11 | "exclude": ["node_modules", "**/*.cy.ts", "**/*.cy.tsx", "**/*.stories.tsx"]
12 | }
13 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_belize_hcw.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_belize_hcw'] {
2 | --_ui5wcr_Scrollbar_Border: 0.0625rem solid #585858;
3 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
4 | --_ui5wcr_Scrollbar_BorderRadius: 0;
5 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
6 | }
7 |
--------------------------------------------------------------------------------
/packages/main/src/components/ObjectPageHeader/ObjectPageHeader.module.css:
--------------------------------------------------------------------------------
1 | .header {
2 | background-color: var(--sapObjectHeader_Background);
3 | position: sticky;
4 | z-index: 1;
5 | padding-block-start: 1rem;
6 | padding-block-end: 1rem;
7 | display: var(--_ui5wcr_ObjectPage_header_display);
8 | overflow: hidden;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "target": "es2022",
5 | "lib": ["ES2023", "dom"],
6 | "noEmitOnError": true,
7 | "strict": true,
8 | "types": ["node"],
9 | "skipLibCheck": true
10 | },
11 | "include": ["src", "**/*.json", "patches"]
12 | }
13 |
--------------------------------------------------------------------------------
/packages/cypress-commands/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "module": "NodeNext",
5 | "moduleResolution": "NodeNext",
6 | "noEmitOnError": true,
7 | "types": ["cypress"],
8 | "strict": true,
9 | "skipLibCheck": true
10 | },
11 | "include": ["src", "test"]
12 | }
13 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | [production]
2 | last 2 Safari versions
3 | last 2 Chrome versions
4 | last 2 Edge versions
5 | last 2 Firefox versions
6 | last 2 iOS versions
7 | last 2 ChromeAndroid versions
8 | last 2 FirefoxAndroid versions
9 |
10 | [development]
11 | last 1 chrome version
12 | last 1 edge version
13 | last 1 safari version
14 | last 1 firefox version
15 |
--------------------------------------------------------------------------------
/docs/ReadMeAI.mdx:
--------------------------------------------------------------------------------
1 | import { Footer, TableOfContent } from '@sb/components';
2 | import { Markdown, Meta } from '@storybook/addon-docs/blocks';
3 | import ReadMe from '../packages/ai/README.md?raw';
4 |
5 |
6 |
7 |
8 |
9 | {ReadMe.split('## Documentation')[0].trim()}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/packages/charts/src/interfaces/index.ts:
--------------------------------------------------------------------------------
1 | import type { TooltipProps } from 'recharts';
2 |
3 | export type TooltipLabelFormatter = TooltipProps<
4 | number | string | Array,
5 | number | string
6 | >['labelFormatter'];
7 |
8 | export type ValueType = number | string | Array;
9 | export type NameType = number | string;
10 |
--------------------------------------------------------------------------------
/templates/nextjs-app/app/globals.css:
--------------------------------------------------------------------------------
1 | /* to prevent flickering, only show the web-component when its custom-element is defined */
2 | :not(:defined) {
3 | display: none;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100vw;
10 | height: 100vh;
11 | background: var(--sapBackgroundColor);
12 | font-family: var(--sapFontFamily);
13 | }
14 |
--------------------------------------------------------------------------------
/packages/main/src/internal/getRandomId.ts:
--------------------------------------------------------------------------------
1 | export const getRandomId = () => {
2 | if ('randomUUID' in crypto) {
3 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
4 | // @ts-ignore
5 | return crypto.randomUUID();
6 | }
7 | const uint32 = window.crypto.getRandomValues(new Uint32Array(1))[0];
8 | return uint32.toString(16);
9 | };
10 |
--------------------------------------------------------------------------------
/packages/ai/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "noImplicitAny": false,
6 | "strictNullChecks": false,
7 | "isolatedModules": true
8 | },
9 | "references": [
10 | {
11 | "path": "../base/tsconfig.json"
12 | }
13 | ],
14 | "include": ["src/**/*"]
15 | }
16 |
--------------------------------------------------------------------------------
/packages/main/src/enums/AnalyticalTableNoDataReason.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Different reasons why the `NoDataComponent` is displayed.
3 | */
4 | export enum AnalyticalTableNoDataReason {
5 | /*
6 | * No data was passed to the table.
7 | */
8 | Empty = 'Empty',
9 | /*
10 | * No results match the applied filters.
11 | */
12 | Filtered = 'Filtered',
13 | }
14 |
--------------------------------------------------------------------------------
/docs/Changelog.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Markdown } from '@storybook/addon-docs/blocks';
2 | import Changelog from '../CHANGELOG.md?raw';
3 | import { Footer, TableOfContent } from '@sb/components';
4 |
5 |
6 |
7 |
8 |
9 | {Changelog}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/packages/base/src/internal/types/Ui5CustomEvent.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * ⚠️ __INTERNAL__ use only! This interface is not part of the public API.
3 | */
4 | export interface Ui5CustomEvent extends Omit<
5 | CustomEvent,
6 | 'target' | 'currentTarget'
7 | > {
8 | target: EventTarget;
9 | currentTarget: EventTarget | null;
10 | }
11 |
--------------------------------------------------------------------------------
/packages/charts/src/components/PieChart/PieChart.module.css:
--------------------------------------------------------------------------------
1 | .piechart {
2 | g:focus,
3 | path:focus {
4 | outline: none;
5 | }
6 |
7 | [data-active-legend] {
8 | background: color-mix(in srgb, var(--sapSelectedColor), transparent 87%);
9 | :global(.recharts-legend-item-text) {
10 | color: var(--sapTextColor) !important;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/vite-ts/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/templates/vite-ts/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/packages/main/src/enums/Theme.ts:
--------------------------------------------------------------------------------
1 | export enum Theme {
2 | sap_fiori_3 = 'sap_fiori_3',
3 | sap_fiori_3_dark = 'sap_fiori_3_dark',
4 | sap_fiori_3_hcb = 'sap_fiori_3_hcb',
5 | sap_fiori_3_hcw = 'sap_fiori_3_hcw',
6 | sap_horizon = 'sap_horizon',
7 | sap_horizon_dark = 'sap_horizon_dark',
8 | sap_horizon_hcb = 'sap_horizon_hcb',
9 | sap_horizon_hcw = 'sap_horizon_hcw',
10 | }
11 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2021",
4 | "lib": ["es2022", "dom"],
5 | "types": ["cypress", "node", "@testing-library/cypress", "cypress-real-events", "chai"],
6 | "moduleResolution": "bundler",
7 | "jsx": "react-jsx",
8 | "composite": true
9 | },
10 | "include": ["cypress", "**/*.cy.ts", "**/*.cy.tsx", "cypress.config.ts"]
11 | }
12 |
--------------------------------------------------------------------------------
/packages/charts/src/hooks/useChartMargin.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react';
2 |
3 | export const useChartMargin = (margin, hasZoomingTool) =>
4 | useMemo(() => {
5 | return {
6 | right: margin?.right ?? 30,
7 | top: (margin?.top ?? hasZoomingTool) ? 40 : 20,
8 | bottom: margin?.bottom ?? 20,
9 | left: margin?.left ?? 10,
10 | };
11 | }, [margin, hasZoomingTool]);
12 |
--------------------------------------------------------------------------------
/packages/main/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "noImplicitAny": false,
6 | "strictNullChecks": false,
7 | "isolatedModules": true,
8 | "emitDeclarationOnly": true
9 | },
10 | "references": [
11 | {
12 | "path": "../base/tsconfig.json"
13 | }
14 | ],
15 | "include": ["src"]
16 | }
17 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_fiori_3.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_fiori_3'] {
2 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
3 | --_ui5wcr_Splitter_BarBorderFocus: 0.0625rem dotted var(--sapContent_FocusColor);
4 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
5 | --_ui5wcr_Splitter_BarBorderHighContrastFix: 0.0625rem dotted var(--sapContent_FocusColor);
6 | }
7 |
--------------------------------------------------------------------------------
/.storybook/components/LabelWithWrapping.tsx:
--------------------------------------------------------------------------------
1 | import WrappingType from '@ui5/webcomponents/dist/types/WrappingType.js';
2 | import { Label } from '@ui5/webcomponents-react';
3 |
4 | //mdx adds a paragraph to children if added inline, this component prevents that.
5 | export const LabelWithWrapping = ({ children }: { children: string }) => {
6 | return {children} ;
7 | };
8 |
--------------------------------------------------------------------------------
/docs/ReadMeCompat.mdx:
--------------------------------------------------------------------------------
1 | import { Footer, TableOfContent } from '@sb/components';
2 | import { Markdown, Meta } from '@storybook/addon-docs/blocks';
3 | import ReadMe from '../packages/compat/README.md?raw';
4 |
5 |
6 |
7 |
8 |
9 | {ReadMe.split('## Documentation')[0].trim()}
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/packages/main/src/components/ObjectPage/context.ts:
--------------------------------------------------------------------------------
1 | import { createContext, useContext } from 'react';
2 | import { ObjectPageMode } from '../../enums/ObjectPageMode.js';
3 | import type { ObjectPagePropTypes } from './types/index.js';
4 |
5 | export const ObjectPageContext = createContext(ObjectPageMode.Default);
6 |
7 | export const useObjectPageContext = () => useContext(ObjectPageContext);
8 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_fiori_3_dark.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_fiori_3_dark'] {
2 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
3 | --_ui5wcr_Splitter_BarBorderFocus: 0.0625rem dotted var(--sapContent_FocusColor);
4 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
5 | --_ui5wcr_Splitter_BarBorderHighContrastFix: 0.0625rem dotted var(--sapContent_FocusColor);
6 | }
7 |
--------------------------------------------------------------------------------
/examples/vite-ts/src/App.cy.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from '@ui5/webcomponents-react';
2 |
3 | describe('Component tests', () => {
4 | // example for component test
5 | it('basic', () => {
6 | const clickSpy = cy.spy().as('clickSpy');
7 | cy.mount(Click me! );
8 | cy.get('[ui5-button]').click();
9 | cy.get('@clickSpy').should('have.been.calledOnce');
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/packages/base/src/internal/hooks/index.ts:
--------------------------------------------------------------------------------
1 | import { useCurrentTheme } from './useCurrentTheme.js';
2 | import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';
3 | import { useIsRTL } from './useIsRTL.js';
4 | import { useStylesheet } from './useStylesheet.js';
5 | import { useSyncRef } from './useSyncRef.js';
6 |
7 | export { useIsomorphicLayoutEffect, useIsRTL, useSyncRef, useStylesheet, useCurrentTheme };
8 |
--------------------------------------------------------------------------------
/packages/base/src/types/index.ts:
--------------------------------------------------------------------------------
1 | import type { ReactElement } from 'react';
2 | import type { ReducedReactNode } from '../internal/types/index.js';
3 |
4 | type InternalUI5WCSlotsNode =
5 | | ReducedReactNode
6 | | Iterable
7 | | false
8 | | ReactElement /* necessary for React v16 & v17 ReactNode type*/;
9 |
10 | export type UI5WCSlotsNode = InternalUI5WCSlotsNode | InternalUI5WCSlotsNode[];
11 |
--------------------------------------------------------------------------------
/types.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md' {
2 | const content: string;
3 | export default content;
4 | }
5 |
6 | declare module '*.png' {
7 | const content: string;
8 | export default content;
9 | }
10 | declare module '*.jpg' {
11 | const content: string;
12 | export default content;
13 | }
14 |
15 | declare module '*.module.css' {
16 | const content: Record;
17 | export default content;
18 | }
19 |
--------------------------------------------------------------------------------
/.storybook/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ArgTypesWithNote.js';
2 | export * from './ControlsWithNote.js';
3 | export * from './DocsHeader.js';
4 | export * from './Footer.js';
5 | export * from './ProductsTable.js';
6 | export * from './ProjectTemplate.js';
7 | export * from './TableOfContent.js';
8 | export * from './LabelWithWrapping.js';
9 | export * from './CommandsAndQueries.js';
10 | export * from './FilterBarExample.js';
11 |
--------------------------------------------------------------------------------
/docs/styling/MyCustomElement.tsx:
--------------------------------------------------------------------------------
1 | import { ThemingParameters } from '@ui5/webcomponents-react-base';
2 | import './MyCustomElement.css';
3 |
4 | export const MyCustomElement = () => {
5 | return (
6 |
7 |
8 | My Text
9 |
10 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/examples/vite-ts/cypress/e2e/App.cy.tsx:
--------------------------------------------------------------------------------
1 | // make sure to start your dev server before running e2e tests
2 | describe('E2E tests', () => {
3 | it('click list item', () => {
4 | cy.visit('/');
5 | cy.clickUi5ListItemByText("Solve a Rubik's cube");
6 | cy.url().should('eq', 'http://localhost:5173/todo/5');
7 | cy.get('[value="Solve a Rubik\'s cube"]').should('be.visible').and('have.attr', 'ui5-input');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/packages/charts/src/components/TimelineChart/util/error.ts:
--------------------------------------------------------------------------------
1 | export class IllegalConnectionError extends Error {
2 | public constructor(message: string) {
3 | super(message);
4 | this.name = 'IllegalConnectionError';
5 | }
6 | }
7 |
8 | export class InvalidDiscreteLabelError extends Error {
9 | public constructor(message: string) {
10 | super(message);
11 | this.name = 'InvalidDiscreteLabelError';
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/cli/src/scripts/resolve-cem/main.ts:
--------------------------------------------------------------------------------
1 | import { writeFile } from 'node:fs/promises';
2 | import { recursiveManifestResolver } from '../../util/recursiveManifestResolver.js';
3 |
4 | export default async function resolveCustomElementManifest(packageName: string, outPath: string) {
5 | const customElementManifest = recursiveManifestResolver(packageName);
6 | await writeFile(outPath, JSON.stringify(customElementManifest, null, 2));
7 | }
8 |
--------------------------------------------------------------------------------
/packages/compat/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "strict": true,
5 | "noImplicitAny": false,
6 | "strictNullChecks": false,
7 | "isolatedModules": true
8 | },
9 | "references": [
10 | {
11 | "path": "../base/tsconfig.json"
12 | },
13 | {
14 | "path": "../main/tsconfig.json"
15 | }
16 | ],
17 | "include": ["src/**/*"]
18 | }
19 |
--------------------------------------------------------------------------------
/docs/styling/CssPartsExample.tsx:
--------------------------------------------------------------------------------
1 | import { composeStories } from '@storybook/react';
2 | import * as CardStories from '../../packages/main/src/webComponents/Card/Card.stories.js';
3 | import './CssPartsExample.css';
4 |
5 | const { Default: CardComponent } = composeStories(CardStories);
6 |
7 | export const CssPartsExample = () => {
8 | return (
9 |
10 |
11 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/loading.tsx:
--------------------------------------------------------------------------------
1 | import { BusyIndicator } from '@ui5/webcomponents-react';
2 | import classes from './loading.module.css';
3 |
4 | import BusyIndicatorSize from '@ui5/webcomponents/dist/types/BusyIndicatorSize.js';
5 |
6 | export default function HomeLoading() {
7 | return (
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_belize.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_belize'] {
2 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
3 | --_ui5wcr_Scrollbar_BorderRadius: 0;
4 | --_ui5wcr_Splitter_BarBorderFocus: 0.0625rem dotted var(--sapContent_FocusColor);
5 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
6 | --_ui5wcr_Splitter_BarBorderHighContrastFix: 0.0625rem dotted var(--sapContent_FocusColor);
7 | }
8 |
--------------------------------------------------------------------------------
/packages/main/src/enums/ObjectPageMode.ts:
--------------------------------------------------------------------------------
1 | export enum ObjectPageMode {
2 | /**
3 | * All `ObjectPageSections` and `ObjectPageSubSections` are displayed on one page.
4 | * Selecting tabs will scroll to the corresponding section.
5 | */
6 | Default = 'Default',
7 | /**
8 | * All `ObjectPageSections` are displayed on separate pages.
9 | * Selecting tabs will lead to the corresponding page.
10 | */
11 | IconTabBar = 'IconTabBar',
12 | }
13 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/README.md:
--------------------------------------------------------------------------------
1 | # UI5 Web Components for React - Navigation Layout Page Pattern
2 |
3 | ## How to use this pattern
4 |
5 | ```bash
6 | npx degit UI5/webcomponents-react/patterns/tool-page#main my-project
7 | cd my-project
8 | ```
9 |
10 | ## Getting Started
11 |
12 | First, install the `node_modules`:
13 |
14 | ```bash
15 | npm install
16 | ```
17 |
18 | Then, run the development server:
19 |
20 | ```bash
21 | npm run dev
22 | ```
23 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | charset = utf-8
11 |
12 | # Indentation override for all JS under lib directory
13 | [*.{js,jsx,ts,tsx}]
14 | indent_style = space
15 | indent_size = 2
16 | quote_type = single
17 |
18 | [makefile]
19 | indent_style = tab
20 |
--------------------------------------------------------------------------------
/config/layers-plugin.js:
--------------------------------------------------------------------------------
1 | function cssLayersPlugin() {
2 | return {
3 | postcssPlugin: 'css-layers-plugin',
4 | Once(root, { AtRule }) {
5 | const layer = new AtRule({
6 | name: 'layer',
7 | params: 'ui5-webcomponents-react',
8 | nodes: root.nodes,
9 | });
10 | root.removeAll();
11 | root.append(layer);
12 | },
13 | };
14 | }
15 |
16 | cssLayersPlugin.postcss = true;
17 |
18 | export default cssLayersPlugin;
19 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Switch/Switch.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { Switch } from './index.js';
3 |
4 | const meta = {
5 | title: 'Inputs / Switch',
6 | component: Switch,
7 | argTypes: {},
8 | args: {},
9 | tags: ['package:@ui5/webcomponents'],
10 | } satisfies Meta;
11 |
12 | export default meta;
13 | type Story = StoryObj;
14 |
15 | export const Default: Story = {};
16 |
--------------------------------------------------------------------------------
/packages/cypress-commands/Queries.mdx:
--------------------------------------------------------------------------------
1 | import { CommandsAndQueries, Footer, TableOfContent } from '@sb/components';
2 | import { Meta } from '@storybook/addon-docs/blocks';
3 | import API from './api-queries.json';
4 |
5 |
6 |
7 |
8 |
9 | # Queries
10 |
11 | Here you can find all available Queries of the `@ui5/webcomponents-cypress-commands` package.
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/templates/vite-ts/src/main.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-react/dist/Assets.js';
2 | import { ThemeProvider } from '@ui5/webcomponents-react';
3 | import { StrictMode } from 'react';
4 | import { createRoot } from 'react-dom/client';
5 | import App from './App.tsx';
6 | import './index.css';
7 |
8 | createRoot(document.getElementById('root') as HTMLElement).render(
9 |
10 |
11 |
12 |
13 | ,
14 | );
15 |
--------------------------------------------------------------------------------
/examples/vite-ts/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress';
2 |
3 | export default defineConfig({
4 | includeShadowDom: true,
5 | viewportWidth: 1920,
6 | viewportHeight: 1080,
7 | component: {
8 | devServer: {
9 | framework: 'react',
10 | bundler: 'vite',
11 | },
12 | },
13 |
14 | e2e: {
15 | baseUrl: 'http://localhost:5173/',
16 | setupNodeEvents() {
17 | // implement node event listeners here
18 | },
19 | },
20 | });
21 |
--------------------------------------------------------------------------------
/packages/charts/src/hooks/useTooltipFormatter.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react';
2 |
3 | export const useTooltipFormatter = (measures) => {
4 | return useCallback(
5 | (value, name, props) => {
6 | const measure = measures.find(({ accessor }) => accessor === props.dataKey);
7 | if (measure && typeof measure.formatter === 'function') {
8 | return measure.formatter(value);
9 | }
10 | return value;
11 | },
12 | [measures],
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/packages/cypress-commands/Commands.mdx:
--------------------------------------------------------------------------------
1 | import { CommandsAndQueries, Footer, TableOfContent } from '@sb/components';
2 | import { Meta } from '@storybook/addon-docs/blocks';
3 | import API from './api-commands.json';
4 |
5 |
6 |
7 |
8 |
9 | # Commands
10 |
11 | Here you can find all available Commands of the `@ui5/webcomponents-cypress-commands` package.
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/packages/main/src/internal/safeGetChildrenArray.ts:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 | import { Children, isValidElement } from 'react';
3 |
4 | export const safeGetChildrenArray = >(children: unknown): T[] => {
5 | const childArray = [];
6 |
7 | Children.forEach(children, (child) => {
8 | if (isValidElement(child)) {
9 | childArray.push(child);
10 | }
11 | });
12 |
13 | return childArray as T[];
14 | };
15 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/src/main.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-react/dist/Assets.js';
2 | import { ThemeProvider } from '@ui5/webcomponents-react';
3 | import { StrictMode } from 'react';
4 | import { createRoot } from 'react-dom/client';
5 | import App from './App.tsx';
6 | import './index.css';
7 |
8 | createRoot(document.getElementById('root') as HTMLElement).render(
9 |
10 |
11 |
12 |
13 | ,
14 | );
15 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @see https://prettier.io/docs/configuration
3 | * @type {import("prettier").Config}
4 | */
5 | const config = {
6 | printWidth: 120,
7 | singleQuote: true,
8 | arrowParens: 'always',
9 | trailingComma: 'all',
10 | embeddedLanguageFormatting: 'auto',
11 | overrides: [
12 | {
13 | files: '*.mdx',
14 | options: {
15 | embeddedLanguageFormatting: 'off',
16 | },
17 | },
18 | ],
19 | };
20 |
21 | export default config;
22 |
--------------------------------------------------------------------------------
/.storybook/components/SplitterElementContent.tsx:
--------------------------------------------------------------------------------
1 | import { FlexBox, Text } from '@ui5/webcomponents-react';
2 | import type { CSSProperties } from 'react';
3 |
4 | export const SplitterElementContent = ({
5 | text,
6 | background = 'transparent',
7 | }: {
8 | text: string;
9 | background: CSSProperties['background'];
10 | }) => (
11 |
12 | {text}
13 |
14 | );
15 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/hooks/useIsFirefox.ts:
--------------------------------------------------------------------------------
1 | // When reused, move to base pkg
2 | import { isFirefox as isFirefoxFn } from '@ui5/webcomponents-react-base/Device';
3 | import { useEffect, useState } from 'react';
4 |
5 | /**
6 | * SSR ready `isFirefox` check.
7 | */
8 | export function useIsFirefox() {
9 | const [isFirefox, setIsFirefox] = useState(false);
10 |
11 | useEffect(() => {
12 | setIsFirefox(isFirefoxFn());
13 | }, []);
14 |
15 | return isFirefox;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/main/src/enums/AnalyticalTableSelectionMode.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Defines the `SelectionMode` of the AnalyticalTable.
3 | */
4 | export enum AnalyticalTableSelectionMode {
5 | /**
6 | * The rows are not selectable.
7 | */
8 | None = 'None',
9 | /**
10 | * Only a single row is selectable. Clicking on another row will unselect the previously selected row.
11 | */
12 | Single = 'Single',
13 | /**
14 | * Multiple rows are selectable.
15 | */
16 | Multiple = 'Multiple',
17 | }
18 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ColorPicker/ColorPicker.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { ColorPicker } from './index.js';
3 |
4 | const meta = {
5 | title: 'Inputs / ColorPicker',
6 | component: ColorPicker,
7 | argTypes: {},
8 | args: {},
9 | tags: ['package:@ui5/webcomponents'],
10 | } satisfies Meta;
11 |
12 | export default meta;
13 | type Story = StoryObj;
14 |
15 | export const Default: Story = {};
16 |
--------------------------------------------------------------------------------
/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/docs/MigrationGuide.css:
--------------------------------------------------------------------------------
1 | h1#migration-guide-v1-to-v2 ~ h2 {
2 | margin-block-start: 5rem;
3 | }
4 |
5 | h1#migration-guide-v1-to-v2 ~ h3 {
6 | border-start-start-radius: 3px;
7 | border-end-start-radius: 3px;
8 | padding-inline-start: 0.25rem;
9 | background: linear-gradient(to right, var(--sapInformationColor) -500%, transparent 100%);
10 | }
11 |
12 | h1#migration-guide-v1-to-v2 ~ h3:dir(rtl) {
13 | background: linear-gradient(to left, var(--sapInformationColor) -500%, transparent 100%);
14 | }
15 |
--------------------------------------------------------------------------------
/packages/main/src/components/ObjectPage/CollapsedAvatar.module.css:
--------------------------------------------------------------------------------
1 | .base {
2 | align-self: center;
3 | opacity: 0;
4 | padding-inline-end: 1rem;
5 | }
6 |
7 | .hidden {
8 | opacity: 0;
9 | }
10 |
11 | .visible {
12 | transition: opacity 0.5s;
13 | opacity: 1;
14 | }
15 |
16 | .imageContainer {
17 | display: inline-block;
18 | vertical-align: middle;
19 | max-height: 3rem;
20 | width: 3rem;
21 | max-width: 3rem;
22 | }
23 |
24 | .image {
25 | width: 100%;
26 | height: 100%;
27 | }
28 |
--------------------------------------------------------------------------------
/packages/main/src/internal/MessageViewContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 | import type { MessageItemPropTypes } from '../components/MessageItem/index.js';
3 |
4 | export type SelectedMessage = MessageItemPropTypes & { titleTextStr: string };
5 |
6 | interface MessageViewContextType {
7 | selectMessage: (message: SelectedMessage) => void;
8 | }
9 |
10 | export const MessageViewContext = createContext({
11 | selectMessage: (_message: SelectedMessage) => {},
12 | });
13 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Icon/Icon.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Icon.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Link/Link.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Link.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Text/Text.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Text.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/hooks/useCanUseVoiceOver.ts:
--------------------------------------------------------------------------------
1 | import { isIOS, isMac } from '@ui5/webcomponents-react-base/Device';
2 | import { useEffect, useState } from 'react';
3 |
4 | /**
5 | * SSR ready check for macOS or iOS (Apple VoiceOver support).
6 | */
7 | export function useCanUseVoiceOver() {
8 | const [canUseVoiceOver, setCanUseVoiceOver] = useState(false);
9 |
10 | useEffect(() => {
11 | setCanUseVoiceOver(isIOS() || isMac());
12 | }, []);
13 |
14 | return canUseVoiceOver;
15 | }
16 |
--------------------------------------------------------------------------------
/packages/main/src/components/FlexBox/FlexBox.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './FlexBox.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Label/Label.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Label.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Title/Title.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Title.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/components/Grid/Grid.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Grid.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/RatingIndicator/RatingIndicator.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { RatingIndicator } from './index.js';
3 |
4 | const meta = {
5 | title: 'Inputs / RatingIndicator',
6 | component: RatingIndicator,
7 | argTypes: {},
8 | args: {},
9 | tags: ['package:@ui5/webcomponents'],
10 | } satisfies Meta;
11 |
12 | export default meta;
13 | type Story = StoryObj;
14 |
15 | export const Default: Story = {};
16 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/TextArea/TextArea.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './TextArea.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/nextjs-app/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'eslint/config';
2 | import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
3 | import nextTypescript from 'eslint-config-next/typescript';
4 | import path from 'node:path';
5 | import { fileURLToPath } from 'node:url';
6 |
7 | const __filename = fileURLToPath(import.meta.url);
8 | const __dirname = path.dirname(__filename);
9 |
10 | export default defineConfig([
11 | {
12 | extends: [...nextCoreWebVitals, ...nextTypescript],
13 | },
14 | ]);
15 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'eslint/config';
2 | import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
3 | import nextTypescript from 'eslint-config-next/typescript';
4 | import path from 'node:path';
5 | import { fileURLToPath } from 'node:url';
6 |
7 | const __filename = fileURLToPath(import.meta.url);
8 | const __dirname = path.dirname(__filename);
9 |
10 | export default defineConfig([
11 | {
12 | extends: [...nextCoreWebVitals, ...nextTypescript],
13 | },
14 | ]);
15 |
--------------------------------------------------------------------------------
/examples/vite-ts/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Slider/Slider.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { Slider } from './index.js';
3 |
4 | const meta = {
5 | title: 'Inputs / Slider',
6 | component: Slider,
7 | argTypes: {
8 | children: { control: { disable: true } },
9 | },
10 | args: {},
11 | tags: ['package:@ui5/webcomponents'],
12 | } satisfies Meta;
13 |
14 | export default meta;
15 | type Story = StoryObj;
16 |
17 | export const Default: Story = {};
18 |
--------------------------------------------------------------------------------
/templates/nextjs-app/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'eslint/config';
2 | import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
3 | import nextTypescript from 'eslint-config-next/typescript';
4 | import path from 'node:path';
5 | import { fileURLToPath } from 'node:url';
6 |
7 | const __filename = fileURLToPath(import.meta.url);
8 | const __dirname = path.dirname(__filename);
9 |
10 | export default defineConfig([
11 | {
12 | extends: [...nextCoreWebVitals, ...nextTypescript],
13 | },
14 | ]);
15 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'eslint/config';
2 | import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
3 | import nextTypescript from 'eslint-config-next/typescript';
4 | import path from 'node:path';
5 | import { fileURLToPath } from 'node:url';
6 |
7 | const __filename = fileURLToPath(import.meta.url);
8 | const __dirname = path.dirname(__filename);
9 |
10 | export default defineConfig([
11 | {
12 | extends: [...nextCoreWebVitals, ...nextTypescript],
13 | },
14 | ]);
15 |
--------------------------------------------------------------------------------
/templates/vite-ts/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/main/src/enums/FlexBoxWrap.ts:
--------------------------------------------------------------------------------
1 | export enum FlexBoxWrap {
2 | /**
3 | * All will stay on one line.
4 | * Note: Corresponds to `nowrap`.
5 | */
6 | NoWrap = 'NoWrap',
7 | /**
8 | * Items will wrap onto multiple lines. (top to bottom)
9 | * Note: Corresponds to `wrap`.
10 | */
11 | Wrap = 'Wrap',
12 | /**
13 | * Items will wrap onto multiple lines. (bottom to top)
14 | * Note: Corresponds to `wrap-reverse`.
15 | */
16 | WrapReverse = 'WrapReverse',
17 | }
18 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Avatar/Avatar.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Avatar.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ColorPicker/ColorPicker.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './ColorPicker.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/DatePicker/DatePicker.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './DatePicker.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Slider/Slider.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Slider.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Switch/Switch.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Switch.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/components/SplitterLayout/SplitterLayout.module.css:
--------------------------------------------------------------------------------
1 | .splitterLayout {
2 | --_ui5wcr-SplitterSize: 1rem;
3 |
4 | display: flex;
5 | overflow: hidden;
6 | position: relative;
7 |
8 | &[data-splitter-orientation='horizontal'] {
9 | flex-direction: row;
10 | width: 100%;
11 | & > * {
12 | height: 100%;
13 | }
14 | }
15 |
16 | &[data-splitter-orientation='vertical'] {
17 | flex-direction: column;
18 | height: 100%;
19 | & > * {
20 | width: 100%;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Carousel/Carousel.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Carousel.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Page/Page.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Markdown, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Page.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ToggleButton/ToggleButton.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './ToggleButton.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/react-router-ts/app/globals.css:
--------------------------------------------------------------------------------
1 | /* to prevent flickering, only show the web-component when its custom-element is defined */
2 | :not(:defined) {
3 | display: none;
4 | }
5 |
6 | html,
7 | body {
8 | max-width: 100vw;
9 | overflow-x: hidden;
10 | padding: 0;
11 | margin: 0;
12 | }
13 |
14 | .appShell {
15 | height: 100vh;
16 | width: 100vw;
17 | overflow: hidden;
18 | }
19 |
20 | .appScrollContainer {
21 | height: calc(100vh - 3.25rem);
22 | width: 100vw;
23 | overflow-y: auto;
24 | position: relative;
25 | }
26 |
--------------------------------------------------------------------------------
/packages/charts/src/interfaces/IChartDimension.ts:
--------------------------------------------------------------------------------
1 | export interface IChartDimension {
2 | /**
3 | * A string containing the path to the dataset key this line should display.
4 | * Supports object structures by using `'parent.child'`. Can also be a getter.
5 | */
6 | accessor: string | ((dataset: Record) => string | number);
7 | /**
8 | * function will be called for each data label and allows you to format it according to your needs
9 | */
10 | formatter?: (value: any, payload?: any) => string | number;
11 | }
12 |
--------------------------------------------------------------------------------
/packages/charts/src/internal/staticProps.ts:
--------------------------------------------------------------------------------
1 | import { ThemingParameters } from '@ui5/webcomponents-react-base';
2 |
3 | export const tickLineConfig = { stroke: 'transparent' };
4 | export const tooltipContentStyle = { backgroundColor: ThemingParameters.sapBackgroundColor };
5 | export const tooltipFillOpacity = { fillOpacity: 0.3 };
6 | export const xAxisPadding = { left: 25, right: 25 };
7 | export const brushProps = {
8 | y: 4,
9 | stroke: ThemingParameters.sapObjectHeader_BorderColor,
10 | travellerWidth: 10,
11 | height: 20,
12 | };
13 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/StepInput/StepInput.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './StepInput.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/TimePicker/TimePicker.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './TimePicker.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/enums/ValueColor.ts:
--------------------------------------------------------------------------------
1 | export enum ValueColor {
2 | /**
3 | * Critical value color.
4 | */
5 | Critical = 'Critical',
6 | /**
7 | * Error value color.
8 | */
9 | Error = 'Error',
10 | /**
11 | * Good value color.
12 | */
13 | Good = 'Good',
14 | /**
15 | * Neutral value color.
16 | */
17 | Neutral = 'Neutral',
18 | /**
19 | * None value color.
20 | * _Note_: The None value color is set to prevent the display of tooltip 'Neutral' for numeric content.
21 | */
22 | None = 'None',
23 | }
24 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/AvatarGroup/AvatarGroup.mdx:
--------------------------------------------------------------------------------
1 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
2 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
3 | import * as ComponentStories from './AvatarGroup.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ExpandableText/ExpandableText.mdx:
--------------------------------------------------------------------------------
1 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
2 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
3 | import * as ComponentStories from './ExpandableText.stories.tsx';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/RangeSlider/RangeSlider.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './RangeSlider.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/SplitButton/SplitButton.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './SplitButton.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/nextjs-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/defaults/NoDataComponent/index.tsx:
--------------------------------------------------------------------------------
1 | import type { AnalyticalTablePropTypes } from '../../types/index.js';
2 |
3 | export const DefaultNoDataComponent: AnalyticalTablePropTypes['NoDataComponent'] = (props) => {
4 | const { noDataText, className, accessibleRole } = props;
5 | return (
6 |
7 | {noDataText}
8 |
9 | );
10 | };
11 |
12 | DefaultNoDataComponent.displayName = 'DefaultNoDataComponent';
13 |
--------------------------------------------------------------------------------
/templates/nextjs-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/packages/charts/src/components/ColumnChartWithTrend/ColumnChartWithTrend.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | /*ChartContainer styles*/
3 | font-size: var(--sapFontSmallSize);
4 | color: var(--sapTextColor);
5 | font-family: var(--sapFontFamily);
6 | width: 100%;
7 | height: 400px;
8 | min-height: fit-content;
9 | position: relative;
10 |
11 | display: flex;
12 | flex-direction: column;
13 | }
14 |
15 | .trendContainer {
16 | height: auto;
17 | flex: 0 0 20%;
18 | }
19 |
20 | .chartContainer {
21 | height: auto;
22 | flex-grow: 1;
23 | }
24 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/DateTimePicker/DateTimePicker.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './DateTimePicker.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Label/Label.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { Label } from './index.js';
3 |
4 | const meta = {
5 | title: 'Data Display / Label',
6 | component: Label,
7 | argTypes: {
8 | children: { control: 'text' },
9 | },
10 | args: {
11 | children: 'Label Text',
12 | },
13 | tags: ['package:@ui5/webcomponents'],
14 | } satisfies Meta;
15 |
16 | export default meta;
17 | type Story = StoryObj;
18 |
19 | export const Default: Story = {};
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/RangeSlider/RangeSlider.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { RangeSlider } from './index.js';
3 |
4 | const meta = {
5 | title: 'Inputs / RangeSlider',
6 | component: RangeSlider,
7 | argTypes: {
8 | children: { control: { disable: true } },
9 | },
10 | args: {},
11 | tags: ['package:@ui5/webcomponents'],
12 | } satisfies Meta;
13 |
14 | export default meta;
15 | type Story = StoryObj;
16 |
17 | export const Default: Story = {};
18 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Thank you for your contribution!** 👏
2 |
3 | To get it merged faster, kindly review the checklist below:
4 |
5 | ## Pull Request Checklist
6 |
7 | - [ ] Reviewed the [Contributing Guidelines](https://github.com/UI5/webcomponents-react/blob/main/CONTRIBUTING.md)
8 | - Especially the [How to Contribute](https://github.com/UI5/webcomponents-react/blob/main/CONTRIBUTING.md#contribute-code) section
9 | - [ ] [Correct commit message style](https://github.com/UI5/webcomponents-react/blob/main/docs/Guidelines.md#commit-message-style)
10 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/DateRangePicker/DateRangePicker.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './DateRangePicker.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/RatingIndicator/RatingIndicator.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './RatingIndicator.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/react-router-ts/app/components/AppShell.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-react/dist/Assets.js';
2 | import { ThemeProvider } from '@ui5/webcomponents-react';
3 | import { ReactNode } from 'react';
4 | import { AppShellBar } from './AppShellBar';
5 |
6 | interface AppShellProps {
7 | children?: ReactNode | ReactNode[];
8 | }
9 |
10 | export function AppShell({ children }: AppShellProps) {
11 | return (
12 |
13 |
14 | {children}
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/hooks/useVisibleColumnsWidth.ts:
--------------------------------------------------------------------------------
1 | import type { ReactTableHooks, TableInstance } from '../types/index.js';
2 |
3 | const getVisibleColumnsWidth = (instance: TableInstance) => {
4 | const visibleColumnsWidth = instance.visibleColumns.map((item) => item.totalWidth);
5 | Object.assign(instance, { visibleColumnsWidth });
6 | };
7 |
8 | export const useVisibleColumnsWidth = (hooks: ReactTableHooks) => {
9 | hooks.useInstance.push(getVisibleColumnsWidth);
10 | };
11 | useVisibleColumnsWidth.pluginName = 'useVisibleColumnsWidth';
12 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/DynamicSideContent/DynamicSideContent.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './DynamicSideContent.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ProgressIndicator/ProgressIndicator.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './ProgressIndicator.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/BarcodeScannerDialog/BarcodeScannerDialog.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './BarcodeScannerDialog.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/globals.css:
--------------------------------------------------------------------------------
1 | /* to prevent flickering, only show the web-component when its custom-element is defined */
2 | :not(:defined) {
3 | display: none;
4 | }
5 |
6 | html,
7 | body {
8 | background: var(--sapBackgroundColor);
9 | max-width: 100vw;
10 | overflow-x: hidden;
11 | padding: 0;
12 | margin: 0;
13 | }
14 |
15 | .appShell {
16 | height: 100vh;
17 | width: 100vw;
18 | overflow: hidden;
19 | }
20 |
21 | .appScrollContainer {
22 | height: calc(100vh - 3.25rem);
23 | width: 100vw;
24 | overflow-y: auto;
25 | position: relative;
26 | }
27 |
--------------------------------------------------------------------------------
/packages/charts/src/hooks/useOnClickInternal.ts:
--------------------------------------------------------------------------------
1 | import { enrichEventWithDetails } from '@ui5/webcomponents-react-base';
2 | import { useCallback } from 'react';
3 |
4 | export const useOnClickInternal = (onClick) =>
5 | useCallback(
6 | (payload, event) => {
7 | if (typeof onClick === 'function') {
8 | onClick(
9 | enrichEventWithDetails(event, {
10 | payload: payload?.activePayload?.[0]?.payload,
11 | activePayloads: payload?.activePayload,
12 | }),
13 | );
14 | }
15 | },
16 | [onClick],
17 | );
18 |
--------------------------------------------------------------------------------
/packages/base/src/internal/utils/addCustomCSSWithScoping.ts:
--------------------------------------------------------------------------------
1 | import { attachBoot } from '@ui5/webcomponents-base/dist/Boot.js';
2 | import { addCustomCSS } from '@ui5/webcomponents-base/dist/Theming.js';
3 | import { getUi5TagWithSuffix } from './index.js';
4 |
5 | /**
6 | * ⚠️ __INTERNAL__ use only! This function is not part of the public API.
7 | */
8 | export const addCustomCSSWithScoping = (baseTagName: string, customCSS: string) => {
9 | attachBoot(() => {
10 | const finalTag = getUi5TagWithSuffix(baseTagName);
11 | void addCustomCSS(finalTag, customCSS);
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/packages/cli/src/scripts/create-wrappers/AbstractRenderer.ts:
--------------------------------------------------------------------------------
1 | import type { WebComponentWrapper } from './WebComponentWrapper.js';
2 |
3 | export enum RenderingPhase {
4 | imports = 'imports',
5 | attributes = 'attributes',
6 | props = 'props',
7 | domRef = 'domRef',
8 | component = 'component',
9 | exports = 'exports',
10 | }
11 |
12 | export abstract class AbstractRenderer {
13 | public readonly phase!: RenderingPhase;
14 |
15 | public prepare(_context: WebComponentWrapper) {
16 | // optional
17 | }
18 | abstract render(context: WebComponentWrapper): string;
19 | }
20 |
--------------------------------------------------------------------------------
/packages/cli/src/scripts/create-wrappers/ExportsRenderer.ts:
--------------------------------------------------------------------------------
1 | import dedent from 'dedent';
2 | import { AbstractRenderer, RenderingPhase } from './AbstractRenderer.js';
3 | import type { WebComponentWrapper } from './WebComponentWrapper.js';
4 |
5 | export class ExportsRenderer extends AbstractRenderer {
6 | public phase = RenderingPhase.exports;
7 |
8 | render(context: WebComponentWrapper): string {
9 | return dedent`
10 | export { ${Array.from(context.exportSet).join(', ')} };
11 | export type { ${Array.from(context.typeExportSet).join(', ')} };
12 | `;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/vite-ts/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | UI5 Web Components React - Vite + TS
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/templates/vite-ts/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | UI5 Web Components React - Vite + TS
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/packages/main/src/internal/ContainerQueries.ts:
--------------------------------------------------------------------------------
1 | export const ContainerQueries = {
2 | S: '@container (max-width: 599px)',
3 | M: '@container (min-width: 600px) and (max-width: 1023px)',
4 | L: '@container (min-width: 1024px) and (max-width: 1439px)',
5 | XL: '@container (min-width: 1440px)',
6 | } as const;
7 |
8 | export const ResponsiveContainerPadding = {
9 | [ContainerQueries.S]: { paddingInline: '1rem' },
10 | [ContainerQueries.M]: { paddingInline: '2rem' },
11 | [ContainerQueries.L]: { paddingInline: '2rem' },
12 | [ContainerQueries.XL]: { paddingInline: '3rem' },
13 | } as const;
14 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/src/ClearAllMessageBox.tsx:
--------------------------------------------------------------------------------
1 | import type { MessageBoxPropTypes } from '@ui5/webcomponents-react';
2 | import { MessageBox, Text } from '@ui5/webcomponents-react';
3 |
4 | export function ClearAllMessageBox(props: Pick) {
5 | const { open, onClose } = props;
6 | return (
7 |
8 | Are you sure you want to clear all the notifications?
9 |
10 | );
11 | }
12 |
13 | ClearAllMessageBox.displayName = 'ClearAllMessageBox';
14 |
--------------------------------------------------------------------------------
/packages/charts/src/hooks/useLabelFormatter.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react';
2 | import type { TooltipProps } from 'recharts';
3 | import type { NameType, TooltipLabelFormatter, ValueType } from '../interfaces/index.js';
4 |
5 | export const useLabelFormatter = (formatter: TooltipLabelFormatter) => {
6 | return useCallback(
7 | (label: TooltipProps['label'], payload) => {
8 | if (typeof formatter === 'function') {
9 | return formatter(label, payload);
10 | }
11 | return label;
12 | },
13 | [formatter],
14 | );
15 | };
16 |
--------------------------------------------------------------------------------
/patterns/Docs.mdx:
--------------------------------------------------------------------------------
1 | import {Footer} from '@sb/components';
2 | import {Meta} from '@storybook/addon-docs/blocks';
3 |
4 |
5 |
6 | # Patterns
7 |
8 | This section describes (design) patterns you can use in your application.
9 |
10 | - [UXC Integration: Navigation Layout pattern](/docs/patterns-uxc-integration--docs)
11 | - [Selection Assistant](/patterns-selectionassistant-experimental--docs)
12 |
13 | ## UI5 Web Components Patterns
14 |
15 | Discover additional patterns built with standard UI5 Web Components: https://ui5.github.io/webcomponents/components/patterns/
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/components/AppShell.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import '@ui5/webcomponents-react/dist/Assets.js';
4 | import { AppShellBar } from '@/app/components/AppShellBar';
5 | import { ThemeProvider } from '@ui5/webcomponents-react';
6 | import { ReactNode } from 'react';
7 |
8 | interface AppShellProps {
9 | children?: ReactNode | ReactNode[];
10 | }
11 |
12 | export function AppShell({ children }: AppShellProps) {
13 | return (
14 |
15 |
16 | {children}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/packages/main/src/enums/AnalyticalTableSelectionBehavior.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Defines the selection behavior of the AnalyticalTable.
3 | */
4 | export enum AnalyticalTableSelectionBehavior {
5 | /**
6 | * A selection column is rendered along with the normal columns. The whole row is selectable.
7 | */
8 | Row = 'Row',
9 | /**
10 | * No selection column is rendered along with the normal columns. The whole row is selectable.
11 | */
12 | RowOnly = 'RowOnly',
13 | /**
14 | * The row is only selectable by clicking on the corresponding field in the selection column.
15 | */
16 | RowSelector = 'RowSelector',
17 | }
18 |
--------------------------------------------------------------------------------
/packages/main/src/enums/AnalyticalTablePopinDisplay.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Defines the display of `AnalyticalTable` pop-ins.
3 | *
4 | * @since 2.5.0
5 | */
6 | export enum AnalyticalTablePopinDisplay {
7 | /*
8 | *Inside the table popin, the header is displayed in the first line and cell content is displayed in the next line.
9 | */
10 | Block = 'Block',
11 | /*
12 | * Inside the table popin, cell content is displayed next to the header in the same line.
13 | */
14 | Inline = 'Inline',
15 | /*
16 | *Inside the table popin, only the cell content will be visible.
17 | */
18 | WithoutHeader = 'WithoutHeader',
19 | }
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Tag/Tag.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Tag.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 | ## Example
11 |
12 |
13 |
14 | ## Properties
15 |
16 |
17 |
18 | # More Examples
19 |
20 | ## All available Tag colors
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/hooks/useResizeColumnsConfig.ts:
--------------------------------------------------------------------------------
1 | import type { MouseEvent } from 'react';
2 | import type { ReactTableHooks } from '../types/index.js';
3 |
4 | const useGetResizerProps = (props) => {
5 | return {
6 | ...props,
7 | 'aria-hidden': 'true',
8 | onMouseDown: (e: MouseEvent) => {
9 | e.preventDefault();
10 | props.onMouseDown(e);
11 | },
12 | };
13 | };
14 |
15 | export const useResizeColumnsConfig = (hooks: ReactTableHooks) => {
16 | hooks.getResizerProps.push(useGetResizerProps);
17 | };
18 |
19 | useResizeColumnsConfig.pluginName = 'useResizeColumnsConfig';
20 |
--------------------------------------------------------------------------------
/packages/charts/src/interfaces/IPolarChartConfig.ts:
--------------------------------------------------------------------------------
1 | import type { CSSProperties } from 'react';
2 |
3 | export interface IPolarChartConfig {
4 | paddingAngle?: number;
5 |
6 | innerRadius?: string;
7 | outerRadius?: string;
8 |
9 | polarGridType?: string;
10 |
11 | tooltipItemStyle?: CSSProperties;
12 | tooltipLabelStyle?: CSSProperties;
13 |
14 | /**
15 | * Index of the segment where an additional outer border should be applied as highlight.
16 | */
17 | activeSegment?: number;
18 | /**
19 | * Flag whether the highlighted segment should display its data label.
20 | */
21 | showActiveSegmentDataLabel?: boolean;
22 | }
23 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Panel/Panel.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Panel.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | # More Examples
20 |
21 |
22 |
23 | ## with custom header
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/main/src/components/MessageViewButton/MessageViewButton.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './MessageViewButton.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | ## MessageViewButtons ordered by severity
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/CheckBox/CheckBox.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './CheckBox.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | # More Examples
20 |
21 |
22 |
23 | ## CheckBox states
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | UI5 Web Components React - Navigation Layout Page
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/packages/compat/src/internal/OverflowPopoverContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext, useContext } from 'react';
2 |
3 | const SYMBOL = Symbol.for('@ui5/webcomponents-react/OverflowPopoverContext');
4 |
5 | interface IOverflowPopoverContext {
6 | inPopover: boolean;
7 | }
8 |
9 | const OverflowPopoverContext = createContext({ inPopover: false });
10 |
11 | export function getOverflowPopoverContext(): typeof OverflowPopoverContext {
12 | globalThis[SYMBOL] ??= OverflowPopoverContext;
13 | return globalThis[SYMBOL];
14 | }
15 |
16 | export function useOverflowPopoverContext() {
17 | return useContext(getOverflowPopoverContext());
18 | }
19 |
--------------------------------------------------------------------------------
/packages/main/src/internal/OverflowPopoverContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext, useContext } from 'react';
2 |
3 | const SYMBOL = Symbol.for('@ui5/webcomponents-react/OverflowPopoverContext');
4 |
5 | interface IOverflowPopoverContext {
6 | inPopover: boolean;
7 | }
8 |
9 | const OverflowPopoverContext = createContext({ inPopover: false });
10 |
11 | export function getOverflowPopoverContext(): typeof OverflowPopoverContext {
12 | globalThis[SYMBOL] ??= OverflowPopoverContext;
13 | return globalThis[SYMBOL];
14 | }
15 |
16 | export function useOverflowPopoverContext() {
17 | return useContext(getOverflowPopoverContext());
18 | }
19 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/MessageStrip/MessageStrip.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './MessageStrip.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 | ## Example
11 |
12 |
13 |
14 | ## Properties
15 |
16 |
17 |
18 | # More Examples
19 |
20 | ## MessageStrip with Icon
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Title/Title.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
3 | import { Title } from './index.js';
4 |
5 | const meta = {
6 | title: 'Data Display / Title',
7 | component: Title,
8 | argTypes: {
9 | children: { control: 'text' },
10 | },
11 | args: {
12 | level: TitleLevel.H2,
13 | children: 'Title Text',
14 | },
15 | tags: ['package:@ui5/webcomponents'],
16 | } satisfies Meta;
17 |
18 | export default meta;
19 | type Story = StoryObj;
20 |
21 | export const Default: Story = {};
22 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json",
3 | "version": "2.17.0",
4 | "npmClient": "yarn",
5 | "command": {
6 | "version": {
7 | "allowBranch": "main",
8 | "conventionalCommits": true,
9 | "yes": true,
10 | "preid": "rc",
11 | "message": "chore(release): publish %s [ci skip]",
12 | "forceConventionalGraduate": true
13 | },
14 | "publish": {
15 | "allowBranch": "main",
16 | "conventionalCommits": true,
17 | "yes": true,
18 | "preid": "rc",
19 | "preDistTag": "next",
20 | "message": "chore(release): publish %s [ci skip]"
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/packages/base/src/hooks/useI18nBundle.ts:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import I18nBundle from '@ui5/webcomponents-base/dist/i18nBundle.js';
4 | import { useEffect, useSyncExternalStore } from 'react';
5 | import { I18nStore } from '../internal/stores/I18nStore.js';
6 |
7 | const defaultBundle = new I18nBundle('defaultBundle');
8 |
9 | export const useI18nBundle = (bundleName: string): I18nBundle => {
10 | const bundles = useSyncExternalStore(I18nStore.subscribe, I18nStore.getSnapshot, I18nStore.getServerSnapshot);
11 |
12 | useEffect(() => {
13 | I18nStore.loadBundle(bundleName);
14 | }, [bundleName]);
15 |
16 | return bundles[bundleName] ?? defaultBundle;
17 | };
18 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Bar/Bar.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Bar.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | # More Examples
20 |
21 |
22 |
23 | ## Bar with custom elements
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/TextArea/TextArea.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
3 | import { TextArea } from './index.js';
4 |
5 | const meta = {
6 | title: 'Inputs / TextArea',
7 | component: TextArea,
8 | argTypes: {
9 | valueStateMessage: { control: { disable: true } },
10 | },
11 | args: {
12 | valueState: ValueState.None,
13 | },
14 | tags: ['package:@ui5/webcomponents'],
15 | } satisfies Meta;
16 |
17 | export default meta;
18 | type Story = StoryObj;
19 |
20 | export const Default: Story = {};
21 |
--------------------------------------------------------------------------------
/examples/vite-ts/src/mockImplementations/mockAPIs.ts:
--------------------------------------------------------------------------------
1 | import { todos } from './mockData.ts';
2 |
3 | interface FetchToDosOptions {
4 | delay?: number;
5 | shouldThrow?: boolean;
6 | }
7 |
8 | // Mock API function to return the todos
9 | export function fetchToDos(options: FetchToDosOptions = {}) {
10 | const { delay = 200, shouldThrow } = options;
11 | return new Promise((resolve, reject) => {
12 | // Simulating API call delay with setTimeout
13 | setTimeout(() => {
14 | if (shouldThrow) {
15 | reject(new Error('Error occurred while fetching todos.'));
16 | } else {
17 | resolve(todos);
18 | }
19 | }, delay);
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/StepInput/StepInput.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
3 | import { StepInput } from './index.js';
4 |
5 | const meta = {
6 | title: 'Inputs / StepInput',
7 | component: StepInput,
8 | argTypes: {
9 | valueStateMessage: { control: { disable: true } },
10 | },
11 | args: {
12 | valueState: ValueState.None,
13 | },
14 | tags: ['package:@ui5/webcomponents'],
15 | } satisfies Meta;
16 |
17 | export default meta;
18 | type Story = StoryObj;
19 |
20 | export const Default: Story = {};
21 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "references": [
4 | {
5 | "path": "./packages/base/tsconfig.build.json"
6 | },
7 | {
8 | "path": "./packages/main/tsconfig.build.json"
9 | },
10 | {
11 | "path": "./packages/charts/tsconfig.build.json"
12 | },
13 | {
14 | "path": "./packages/cypress-commands/tsconfig.build.json"
15 | },
16 | {
17 | "path": "./packages/cli/tsconfig.build.json"
18 | },
19 | {
20 | "path": "./packages/compat/tsconfig.build.json"
21 | },
22 | {
23 | "path": "./packages/ai/tsconfig.build.json"
24 | }
25 | ],
26 | "files": []
27 | }
28 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "paths": {
18 | "@/*": ["./src/*"]
19 | }
20 | },
21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
22 | "exclude": ["node_modules"]
23 | }
24 |
--------------------------------------------------------------------------------
/packages/base/src/internal/types/index.ts:
--------------------------------------------------------------------------------
1 | import type { ReactNode, ReactPortal } from 'react';
2 | /**
3 | * ⚠️ __INTERNAL__ use only! This type is not part of the public API.
4 | */
5 | export type ReducedReactNode = Exclude>;
6 | /**
7 | * ⚠️ __INTERNAL__ use only! This type is not part of the public API.
8 | */
9 | export type ReducedReactNodeWithBoolean = Exclude>;
10 |
11 | export type { CommonProps } from './CommonProps.js';
12 | export type { Ui5CustomEvent } from './Ui5CustomEvent.js';
13 | export type { Ui5DomRef } from './Ui5DomRef.js';
14 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ProgressIndicator/ProgressIndicator.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
3 | import { ProgressIndicator } from './index.js';
4 |
5 | const meta = {
6 | title: 'Data Display / ProgressIndicator',
7 | component: ProgressIndicator,
8 | argTypes: {},
9 | args: {
10 | valueState: ValueState.None,
11 | value: 50,
12 | },
13 | tags: ['package:@ui5/webcomponents'],
14 | } satisfies Meta;
15 |
16 | export default meta;
17 | type Story = StoryObj;
18 |
19 | export const Default: Story = {};
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/TimePicker/TimePicker.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
3 | import { TimePicker } from './index.js';
4 |
5 | const meta = {
6 | title: 'Inputs / TimePicker',
7 | component: TimePicker,
8 | argTypes: {
9 | valueStateMessage: { control: { disable: true } },
10 | },
11 | args: {
12 | valueState: ValueState.None,
13 | },
14 | tags: ['package:@ui5/webcomponents'],
15 | } satisfies Meta;
16 |
17 | export default meta;
18 | type Story = StoryObj;
19 |
20 | export const Default: Story = {};
21 |
--------------------------------------------------------------------------------
/templates/nextjs-app/app/page.tsx:
--------------------------------------------------------------------------------
1 | import employeeIcon from '@ui5/webcomponents-icons/dist/employee.js';
2 | import { Avatar, ShellBar } from '@ui5/webcomponents-react';
3 |
4 | export default function Page() {
5 | return (
6 | <>
7 |
13 | }
14 | primaryTitle="UI5 Web Components for React Template"
15 | profile={ }
16 | />
17 | {/* Add your code here */}
18 | >
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/page.tsx:
--------------------------------------------------------------------------------
1 | import { TodoList } from '@/app/components/TodoList';
2 | import { Todo, todos } from '@/app/mockData/todos';
3 | import { Bar, Page, Title } from '@ui5/webcomponents-react';
4 |
5 | export default async function Home() {
6 | // this is a very simple mock which mimics data fetching
7 | const todoList = await new Promise((resolve) => {
8 | setTimeout(() => {
9 | resolve(todos);
10 | }, 1500);
11 | });
12 |
13 | return (
14 | <>
15 | My Todos} />} fixedFooter>
16 |
17 |
18 | >
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import employeeIcon from '@ui5/webcomponents-icons/dist/employee.js';
2 | import { Avatar, ShellBar } from '@ui5/webcomponents-react';
3 |
4 | export default function Home() {
5 | return (
6 | <>
7 |
13 | }
14 | primaryTitle="UI5 Web Components for React Template"
15 | profile={ }
16 | />
17 | {/* Add your code here */}
18 | >
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "react-jsx",
16 | "incremental": true,
17 | "paths": {
18 | "@/*": ["./src/*"]
19 | }
20 | },
21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
22 | "exclude": ["node_modules"]
23 | }
24 |
--------------------------------------------------------------------------------
/templates/vite-ts/src/App.tsx:
--------------------------------------------------------------------------------
1 | import employeeIcon from '@ui5/webcomponents-icons/dist/employee.js';
2 | import { Avatar, ShellBar } from '@ui5/webcomponents-react';
3 | function App() {
4 | return (
5 | <>
6 |
12 | }
13 | primaryTitle="UI5 Web Components for React Template"
14 | profile={ }
15 | />
16 | {/* Add your code here */}
17 | >
18 | );
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/packages/main/src/components/ThemeProvider/ThemeProvider.css:
--------------------------------------------------------------------------------
1 | /*The classes in this file are applied globally */
2 |
3 | @import './Sizes.css';
4 | @import '../../themes/base.css';
5 | @import '../../themes/sap_belize.css';
6 | @import '../../themes/sap_belize_hcb.css';
7 | @import '../../themes/sap_belize_hcw.css';
8 | @import '../../themes/sap_fiori_3.css';
9 | @import '../../themes/sap_fiori_3_dark.css';
10 | @import '../../themes/sap_fiori_3_hcb.css';
11 | @import '../../themes/sap_fiori_3_hcw.css';
12 | @import '../../themes/sap_horizon.css';
13 | @import '../../themes/sap_horizon_dark.css';
14 | @import '../../themes/sap_horizon_hcb.css';
15 | @import '../../themes/sap_horizon_hcw.css';
16 |
--------------------------------------------------------------------------------
/packages/main/src/components/ObjectPageTitle/ActionsSpacer.tsx:
--------------------------------------------------------------------------------
1 | import type { MouseEventHandler } from 'react';
2 |
3 | interface ActionsSpacerProps {
4 | onClick: MouseEventHandler;
5 | noHover?: boolean;
6 | }
7 |
8 | export const ActionsSpacer = ({ onClick, noHover }: ActionsSpacerProps) => {
9 | return (
10 |
16 | );
17 | };
18 |
19 | // The Toolbar only recognizes spacers with the 'ToolbarSpacer' displayName
20 | ActionsSpacer.displayName = 'ToolbarSpacer';
21 |
--------------------------------------------------------------------------------
/packages/base/src/internal/hooks/useCurrentTheme.ts:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { getTheme } from '@ui5/webcomponents-base/dist/config/Theme.js';
4 | import { attachThemeLoaded, detachThemeLoaded } from '@ui5/webcomponents-base/dist/Theming.js';
5 | import { useEffect, useState } from 'react';
6 |
7 | export function useCurrentTheme(): string {
8 | const [theme, setLocalTheme] = useState(getTheme());
9 |
10 | useEffect(() => {
11 | const onThemeSwitch = (newTheme: string) => {
12 | setLocalTheme(newTheme);
13 | };
14 | attachThemeLoaded(onThemeSwitch);
15 | return () => {
16 | detachThemeLoaded(onThemeSwitch);
17 | };
18 | }, []);
19 |
20 | return theme;
21 | }
22 |
--------------------------------------------------------------------------------
/translation_v2.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment": "Translation configuration for ui5-webcomponents-react",
3 | "collections": [
4 | {
5 | "collectionName": "UI5 Web Components for React",
6 | "folders": [
7 | {
8 | "startingFolderPath": "./packages/",
9 | "sourceFilters": ["*/src/**/messagebundle.properties"],
10 | "excludedSourceFilters": []
11 | }
12 | ]
13 | }
14 | ],
15 | "defaultConfiguration": {
16 | "xlfFolderPath": "./XLF/[FullPath]",
17 | "targetFolderPath": ".",
18 | "pseudoLocFolderPath": ".",
19 | "oneQFolderPath": ".",
20 | "targetFileNamingConvention": "[filename]_[langCode].[extension]"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | node_modules
3 | *.iml
4 | yarn-error.log
5 | .idea
6 | /.env
7 | @types
8 | .cache
9 | .out
10 | lerna-debug.log
11 | /temp
12 | *.tsbuildinfo
13 |
14 | .pnp.*
15 | .yarn/*
16 | !.yarn/patches
17 | !.yarn/plugins
18 | !.yarn/releases
19 | !.yarn/sdks
20 | !.yarn/versions
21 |
22 | packages/cypress-commands/api-commands.json
23 | packages/cypress-commands/api-queries.json
24 |
25 | packages/main/scripts/wrapperGeneration/json
26 | packages/main/tmp
27 | packages/*/src/generated/
28 |
29 | cypress/downloads
30 |
31 | .nx
32 |
33 | debug-storybook.log
34 |
35 | .vscode
36 | .cursor/rules/nx-rules.mdc
37 | .github/instructions/nx.instructions.md
38 |
--------------------------------------------------------------------------------
/.pipeline/config.yml:
--------------------------------------------------------------------------------
1 | general:
2 | owner: SAP
3 | repository: ui5-webcomponents-react
4 | buildTool: yarn
5 | steps:
6 | artifactPrepareVersion:
7 | filePath: 'lerna.json'
8 | versioningType: 'library'
9 | customVersionField: 'version'
10 |
11 | detectExecuteScan:
12 | dockerImage: maven:3.8-jdk-11
13 | serverUrl: 'https://sap.blackducksoftware.com'
14 | projectName: 'ui5-webcomponents-react'
15 | groups:
16 | - 'ui5-webcomponents-react'
17 | npmDependencyTypesExcluded: ['DEV']
18 | useDetect9: true
19 | excludedPackageManagers:
20 | - 'LERNA'
21 | customEnvironmentVariables:
22 | - 'DETECT_YARN_DEPENDENCY_TYPES_EXCLUDED=NON_PRODUCTION'
23 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/BusyIndicator/BusyIndicator.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Markdown, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './BusyIndicator.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | # More Examples
20 |
21 |
22 |
23 | ## BusyIndicator with children
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/packages/charts/src/internal/ChartContainer.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | font-size: var(--sapFontSmallSize);
3 | color: var(--sapTextColor);
4 | font-family: var(--sapFontFamily);
5 | width: 100%;
6 | height: 400px;
7 | min-height: fit-content;
8 | position: relative;
9 | }
10 |
11 | .busyIndicator {
12 | background-color: color-mix(in srgb, var(--sapBackgroundColor) 45%, transparent);
13 | position: absolute;
14 | inset: 0;
15 | height: 100%;
16 | z-index: 1;
17 | }
18 |
19 | :global(.has-click-handler) {
20 | :global(.recharts-pie-sector),
21 | :global(.recharts-bar-rectangles),
22 | :global(.recharts-active-dot),
23 | :global(.recharts-area-dot) {
24 | cursor: pointer;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_fiori_3_hcb.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_fiori_3_hcb'] {
2 | --_ui5wcr_Splitter_BarOutline: 0.15rem dotted var(--sapGroup_ContentBorderColor);
3 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
4 | --_ui5wcr_Splitter_BarBorderFocus: solid var(--sapGroup_ContentBorderColor) 0.0625rem;
5 | --_ui5wcr_Splitter_BarBorderStyle: solid var(--sapGroup_ContentBorderColor) 0.0625rem;
6 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
7 | --_ui5wcr_Splitter_ContentBorderColor: var(--sapGroup_ContentBorderColor);
8 | --_ui5wcr_Splitter_BarBorderHighContrastFix: none;
9 | --_ui5wcr_Form_HeaderBorderWidth: calc(3 * var(--sapList_BorderWidth));
10 | }
11 |
--------------------------------------------------------------------------------
/packages/main/src/themes/sap_fiori_3_hcw.css:
--------------------------------------------------------------------------------
1 | [data-sap-theme='sap_fiori_3_hcw'] {
2 | --_ui5wcr_Splitter_BarOutline: 0.15rem dotted var(--sapGroup_ContentBorderColor);
3 | --_ui5wcr_ActionSheet_BoxShadow: var(--sapContent_HeaderShadow);
4 | --_ui5wcr_Splitter_BarBorderFocus: solid var(--sapGroup_ContentBorderColor) 0.0625rem;
5 | --_ui5wcr_Splitter_BarBorderStyle: solid var(--sapGroup_ContentBorderColor) 0.0625rem;
6 | --_ui5wcr_ActionSheet_TopBorderRadius: var(--sapElement_BorderCornerRadius);
7 | --_ui5wcr_Splitter_ContentBorderColor: var(--sapGroup_ContentBorderColor);
8 | --_ui5wcr_Splitter_BarBorderHighContrastFix: none;
9 | --_ui5wcr_Form_HeaderBorderWidth: calc(3 * var(--sapList_BorderWidth));
10 | }
11 |
--------------------------------------------------------------------------------
/packages/main/src/enums/FlexBoxDirection.ts:
--------------------------------------------------------------------------------
1 | export enum FlexBoxDirection {
2 | /**
3 | * Items are placed top to bottom.
4 | * Note: Corresponds to `column`.
5 | */
6 | Column = 'Column',
7 | /**
8 | * Items are placed bottom to top.
9 | * Note: Corresponds to `column-reverse`.
10 | */
11 | ColumnReverse = 'ColumnReverse',
12 | /**
13 | * Items are placed left to right in `ltr` and right to left in `rtl`.
14 | * Note: Corresponds to `row`.
15 | */
16 | Row = 'Row',
17 | /**
18 | * Items are placed right to left in `ltr` and left to right in `rtl`.
19 | * Note: Corresponds to `row-reverse`.
20 | */
21 | RowReverse = 'RowReverse',
22 | }
23 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/pages/api/todos/[id].ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import { fetchTodos, Todo } from '../todos';
3 | import type { NextApiRequest, NextApiResponse } from 'next';
4 |
5 | export async function fetchTodoById(id: string): Promise {
6 | const todos = await fetchTodos();
7 | return todos.find((todo) => `${todo.id}` === id);
8 | }
9 |
10 | export default async function handler(req: NextApiRequest, res: NextApiResponse) {
11 | const todo = await fetchTodoById(req.query.id as string);
12 | if (todo) {
13 | res.status(200).json(todo);
14 | } else {
15 | res.status(404).json({ error: 'Not found' });
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ToggleButton/ToggleButton.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js';
3 | import { ToggleButton } from './index.js';
4 |
5 | const meta = {
6 | title: 'Inputs / ToggleButton',
7 | component: ToggleButton,
8 | argTypes: {
9 | children: { control: 'text' },
10 | },
11 | args: {
12 | design: ButtonDesign.Default,
13 | icon: 'employee',
14 | children: 'ToggleButton Text',
15 | },
16 | tags: ['package:@ui5/webcomponents'],
17 | } satisfies Meta;
18 |
19 | export default meta;
20 | type Story = StoryObj;
21 |
22 | export const Default: Story = {};
23 |
--------------------------------------------------------------------------------
/packages/ai/src/components/PromptInput/PromptInput.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
3 | import { PromptInput } from './index.js';
4 |
5 | const meta = {
6 | title: 'PromptInput',
7 | component: PromptInput,
8 | argTypes: {
9 | children: { control: { disable: true } },
10 | valueStateMessage: { control: { disable: true } },
11 | },
12 | args: {
13 | valueState: ValueState.None,
14 | },
15 | tags: ['package:@ui5/webcomponents-ai', 'experimental'],
16 | } satisfies Meta;
17 |
18 | export default meta;
19 | type Story = StoryObj;
20 |
21 | export const Default: Story = {};
22 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/TableBody/EmptyRow.tsx:
--------------------------------------------------------------------------------
1 | import type { VirtualItem } from '@tanstack/react-virtual';
2 | import type { ReactNode } from 'react';
3 |
4 | export const EmptyRow = ({
5 | virtualRow,
6 | className,
7 | children,
8 | }: {
9 | virtualRow: VirtualItem;
10 | className: string;
11 | children?: ReactNode;
12 | }) => {
13 | return (
14 |
24 | {children}
25 |
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/packages/base/src/hooks/useViewportRange.ts:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import { useEffect, useState } from 'react';
4 | import { getCurrentRange, attachMediaHandler, detachMediaHandler } from '../Device/index.js';
5 |
6 | export const useViewportRange = () => {
7 | const [currentRange, setCurrentRange] = useState(getCurrentRange()?.name);
8 |
9 | useEffect(() => {
10 | let isMounted = true;
11 | const handler = ({ name: range }) => {
12 | if (isMounted === true) {
13 | setCurrentRange(range);
14 | }
15 | };
16 | attachMediaHandler(handler);
17 | return () => {
18 | isMounted = false;
19 | detachMediaHandler(handler);
20 | };
21 | }, [setCurrentRange]);
22 |
23 | return currentRange;
24 | };
25 |
--------------------------------------------------------------------------------
/patterns/selection-assistant/SelectionAssistantContainer.tsx:
--------------------------------------------------------------------------------
1 | import { Card, FlexBox } from '@ui5/webcomponents-react';
2 | import { forwardRef, type ReactNode } from 'react';
3 |
4 | export const SelectionAssistantContainer = forwardRef(({ children }, ref) => {
5 | return (
6 |
7 |
15 | {children}
16 |
17 |
18 | );
19 | });
20 |
21 | SelectionAssistantContainer.displayName = 'SelectionAssistantContainer';
22 |
--------------------------------------------------------------------------------
/packages/base/src/internal/types/CommonProps.ts:
--------------------------------------------------------------------------------
1 | import type { CSSProperties, HTMLAttributes } from 'react';
2 |
3 | /**
4 | * ⚠️ __INTERNAL__ use only! This interface is not part of the public API.
5 | */
6 | export interface CommonProps extends Omit, 'dangerouslySetInnerHTML'> {
7 | /**
8 | * Element style which will be appended to the most outer element of a component.
9 | * Use this prop carefully, some css properties might break the component.
10 | */
11 | style?: CSSProperties;
12 | /**
13 | * CSS Class Name which will be appended to the most outer element of a component.
14 | * Use this prop carefully, overwriting CSS rules might break the component.
15 | */
16 | className?: string;
17 | }
18 |
--------------------------------------------------------------------------------
/examples/vite-ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
5 | "module": "ESNext",
6 | "skipLibCheck": true,
7 | /* Bundler mode */
8 | "moduleResolution": "bundler",
9 | "allowImportingTsExtensions": true,
10 | "resolveJsonModule": true,
11 | "isolatedModules": true,
12 | "noEmit": true,
13 | "jsx": "react-jsx",
14 | /* Linting */
15 | "strict": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noFallthroughCasesInSwitch": true
19 | },
20 | "include": ["src"],
21 | "exclude": ["src/**/*.cy.tsx"],
22 | "references": [
23 | {
24 | "path": "./tsconfig.node.json"
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/packages/main/src/internal/VariantManagementContext.ts:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 | import type { VariantItemPropTypes } from '../components/VariantItem/index.js';
3 | import type { ListItemStandardDomRef } from '../webComponents/ListItemStandard/index.js';
4 |
5 | interface VariantManagementContextTypes {
6 | selectVariantItem: (_selectedVariant: SelectedVariant) => void;
7 | selectedVariant: SelectedVariant;
8 | }
9 |
10 | export interface SelectedVariant extends VariantItemPropTypes {
11 | variantItem: ListItemStandardDomRef;
12 | }
13 |
14 | export const VariantManagementContext = createContext({
15 | selectVariantItem: (_selectedVariant: SelectedVariant) => {},
16 | selectedVariant: undefined,
17 | });
18 |
--------------------------------------------------------------------------------
/templates/vite-ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
5 | "module": "ESNext",
6 | "skipLibCheck": true,
7 | /* Bundler mode */
8 | "moduleResolution": "bundler",
9 | "allowImportingTsExtensions": true,
10 | "resolveJsonModule": true,
11 | "isolatedModules": true,
12 | "noEmit": true,
13 | "jsx": "react-jsx",
14 | /* Linting */
15 | "strict": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noFallthroughCasesInSwitch": true
19 | },
20 | "include": ["src"],
21 | "exclude": ["src/**/*.cy.tsx"],
22 | "references": [
23 | {
24 | "path": "./tsconfig.node.json"
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/examples/nextjs-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "eslint ."
10 | },
11 | "dependencies": {
12 | "@ui5/webcomponents": "2.17.0",
13 | "@ui5/webcomponents-base": "2.17.0",
14 | "@ui5/webcomponents-fiori": "2.17.0",
15 | "@ui5/webcomponents-react": "2.17.0",
16 | "@types/node": "24.10.4",
17 | "@types/react": "19.2.7",
18 | "@types/react-dom": "19.2.3",
19 | "eslint": "9.39.2",
20 | "eslint-config-next": "16.0.10",
21 | "next": "16.0.10",
22 | "react": "19.2.3",
23 | "react-dom": "19.2.3",
24 | "typescript": "5.9.3"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/charts/src/components/RadialChart/RadialChart.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './RadialChart.stories';
4 |
5 |
6 |
7 |
8 |
9 | ## Example
10 |
11 |
12 |
13 | ## Properties
14 |
15 |
16 |
17 |
18 |
19 |
20 | ## More Examples
21 |
22 | ### With Custom Color
23 |
24 |
25 |
26 | ### Micro RadialCharts
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/templates/nextjs-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "eslint ."
10 | },
11 | "dependencies": {
12 | "@ui5/webcomponents": "2.17.0",
13 | "@ui5/webcomponents-base": "2.17.0",
14 | "@ui5/webcomponents-fiori": "2.17.0",
15 | "@ui5/webcomponents-react": "2.17.0",
16 | "@types/node": "24.10.4",
17 | "@types/react": "19.2.7",
18 | "@types/react-dom": "19.2.3",
19 | "eslint": "9.39.2",
20 | "eslint-config-next": "16.0.10",
21 | "next": "16.0.10",
22 | "react": "19.2.3",
23 | "react-dom": "19.2.3",
24 | "typescript": "5.9.3"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/compat/src/components/ToolbarSpacer/index.tsx:
--------------------------------------------------------------------------------
1 | import type { CommonProps } from '@ui5/webcomponents-react/dist/types/CommonProps.js';
2 | import { forwardRef } from 'react';
3 |
4 | export type ToolbarSpacerPropTypes = CommonProps;
5 | /**
6 | * Adds horizontal space between the items used within a `Toolbar`.
7 | *
8 | * __Note:__ This component is only compatible with the `Toolbar` component from the `@ui5/webcomponents-react-compat` package.
9 | */
10 | const ToolbarSpacer = forwardRef((props, ref) => {
11 | return ;
12 | });
13 |
14 | ToolbarSpacer.displayName = 'ToolbarSpacer';
15 | export { ToolbarSpacer };
16 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
5 | "module": "ESNext",
6 | "skipLibCheck": true,
7 | /* Bundler mode */
8 | "moduleResolution": "bundler",
9 | "allowImportingTsExtensions": true,
10 | "resolveJsonModule": true,
11 | "isolatedModules": true,
12 | "noEmit": true,
13 | "jsx": "react-jsx",
14 | /* Linting */
15 | "strict": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noFallthroughCasesInSwitch": true
19 | },
20 | "include": ["src"],
21 | "exclude": ["src/**/*.cy.tsx"],
22 | "references": [
23 | {
24 | "path": "./tsconfig.node.json"
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/pluginHooks/AnalyticalTableHooks.ts:
--------------------------------------------------------------------------------
1 | import { useAnnounceEmptyCells } from './useAnnounceEmptyCells.js';
2 | import { useF2CellEdit } from './useF2CellEdit.js';
3 | import { useIndeterminateRowSelection } from './useIndeterminateRowSelection.js';
4 | import { useManualRowSelect } from './useManualRowSelect.js';
5 | import { useOnColumnResize } from './useOnColumnResize.js';
6 | import { useOrderedMultiSort } from './useOrderedMultiSort.js';
7 | import { useRowDisableSelection } from './useRowDisableSelection.js';
8 |
9 | export {
10 | useAnnounceEmptyCells,
11 | useF2CellEdit,
12 | useIndeterminateRowSelection,
13 | useManualRowSelect,
14 | useOnColumnResize,
15 | useOrderedMultiSort,
16 | useRowDisableSelection,
17 | };
18 |
--------------------------------------------------------------------------------
/packages/main/src/enums/AnalyticalTableScrollMode.ts:
--------------------------------------------------------------------------------
1 | export enum AnalyticalTableScrollMode {
2 | // Scroll as little as possible to ensure the item is visible. (If the item is already visible, it won't scroll at all.)
3 | auto = 'auto',
4 | // If the item is already visible, don't scroll at all. If it is less than one viewport away, scroll as little as possible so that it becomes visible. If it is more than one viewport away, scroll so that it is centered within the list.
5 | center = 'center',
6 | // Align the item to the end of the list (the bottom for vertical lists or the right for horizontal lists).
7 | end = 'end',
8 | // Align the item to the beginning of the list (the top for vertical lists or the left for horizontal lists)
9 | start = 'start',
10 | }
11 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/FileUploader/FileUploader.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './FileUploader.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | ## More Examples
20 |
21 | ### FileUploader with Buttons
22 |
23 |
24 |
25 | ### FileUploader without input field
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Link/Link.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import LinkDesign from '@ui5/webcomponents/dist/types/LinkDesign.js';
3 | import WrappingType from '@ui5/webcomponents/dist/types/WrappingType.js';
4 | import { Link } from './index.js';
5 |
6 | const meta = {
7 | title: 'Data Display / Link',
8 | component: Link,
9 | argTypes: {
10 | children: { control: 'text' },
11 | },
12 | args: {
13 | design: LinkDesign.Default,
14 | wrappingType: WrappingType.None,
15 | children: 'Link Text',
16 | },
17 | tags: ['package:@ui5/webcomponents'],
18 | } satisfies Meta;
19 |
20 | export default meta;
21 | type Story = StoryObj;
22 |
23 | export const Default: Story = {};
24 |
--------------------------------------------------------------------------------
/examples/vite-ts/cypress/support/e2e.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/e2e.ts is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands';
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/packages/base/src/Device/EventProvider.ts:
--------------------------------------------------------------------------------
1 | import EventProviderWC from '@ui5/webcomponents-base/dist/EventProvider.js';
2 |
3 | export type RANGE_LEGACY_4_STEPS = 'Phone' | 'Tablet' | 'Desktop' | 'LargeDesktop';
4 |
5 | export interface RangeInfo {
6 | from: number;
7 | to?: number;
8 | name: RANGE_LEGACY_4_STEPS;
9 | unit: string;
10 | }
11 |
12 | export interface IOrientation {
13 | landscape: boolean;
14 | portrait: boolean;
15 | }
16 |
17 | export interface IWindowSize {
18 | height: number;
19 | width: number;
20 | }
21 |
22 | export const MediaEventProvider = new EventProviderWC();
23 | export const OrientationEventProvider = new EventProviderWC();
24 | export const ResizeEventProvider = new EventProviderWC();
25 |
--------------------------------------------------------------------------------
/.storybook/components/DomRefTable.module.css:
--------------------------------------------------------------------------------
1 | .parameters:not(:last-child) {
2 | margin-block-end: 1rem;
3 | }
4 |
5 | .parameterName {
6 | font-weight: bold;
7 | }
8 |
9 | .parameterDetails {
10 | padding-inline: 1rem;
11 | }
12 |
13 | .domRefCodeBlock {
14 | display: contents;
15 | overflow-x: auto;
16 | padding: 0;
17 | background: white;
18 | color: black;
19 | white-space: pre-wrap;
20 | font-size: 14px;
21 | margin: 0;
22 | }
23 |
24 | .domRefCode {
25 | white-space: pre;
26 |
27 | > span {
28 | font-size: 14px;
29 | }
30 | }
31 |
32 | .deprecationInfoBadge {
33 | margin-top: 0.5rem !important;
34 | }
35 |
36 | .deprecationInfoPopover {
37 | max-width: 15rem;
38 | }
39 |
40 | .deprecationInfoPopover::part(content) {
41 | padding: 0.5rem;
42 | }
43 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-pages",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "eslint ."
10 | },
11 | "dependencies": {
12 | "@ui5/webcomponents": "2.17.0",
13 | "@ui5/webcomponents-base": "2.17.0",
14 | "@ui5/webcomponents-fiori": "2.17.0",
15 | "@ui5/webcomponents-react": "2.17.0",
16 | "@types/node": "24.10.4",
17 | "@types/react": "19.2.7",
18 | "@types/react-dom": "19.2.3",
19 | "eslint": "9.39.2",
20 | "eslint-config-next": "16.0.10",
21 | "next": "16.0.10",
22 | "react": "19.2.3",
23 | "react-dom": "19.2.3",
24 | "typescript": "5.9.3"
25 | },
26 | "devDependencies": {}
27 | }
28 |
--------------------------------------------------------------------------------
/packages/ai/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Button } from './components/Button/index.js';
2 | export { ButtonState } from './components/ButtonState/index.js';
3 | export { Input } from './components/Input/index.js';
4 | export { PromptInput } from './components/PromptInput/index.js';
5 | export { TextArea } from './components/TextArea/index.js';
6 |
7 | export type { ButtonDomRef, ButtonPropTypes } from './components/Button/index.js';
8 | export type { ButtonStateDomRef, ButtonStatePropTypes } from './components/ButtonState/index.js';
9 | export type { InputDomRef, InputPropTypes } from './components/Input/index.js';
10 | export type { PromptInputDomRef, PromptInputPropTypes } from './components/PromptInput/index.js';
11 | export type { TextAreaDomRef, TextAreaPropTypes } from './components/TextArea/index.js';
12 |
--------------------------------------------------------------------------------
/.storybook/components/ProjectTemplate.module.css:
--------------------------------------------------------------------------------
1 | .cardContainer {
2 | position: relative;
3 | width: 500px;
4 | margin-block-end: 2rem;
5 | flex-shrink: 0;
6 | }
7 |
8 | .cardContent {
9 | padding: 1rem;
10 | }
11 |
12 | .deprecationNotice {
13 | margin-block-end: 0.5rem;
14 | }
15 |
16 | .template {
17 | width: 300px;
18 | height: unset;
19 | .unssupportedMessage {
20 | inset-block-end: 70px;
21 | }
22 | }
23 |
24 | .overlay {
25 | opacity: 0.5;
26 | pointer-events: none;
27 | }
28 |
29 | .unssupportedMessage {
30 | position: absolute;
31 | z-index: 1;
32 | inset-block-end: 180px;
33 | inset-inline-start: 5%;
34 | width: 90%;
35 | }
36 |
37 | .popover::part(content) {
38 | padding: 0.5rem;
39 | }
40 |
41 | .verticalLine {
42 | padding-inline: 0.1rem;
43 | }
44 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/FlexibleColumnLayout/FlexibleColumnLayout.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './FlexibleColumnLayout.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | # More Examples
20 |
21 |
22 |
23 | ## FlexibleColumnLayout with different columns
24 |
25 | Click on one of the list items to open the next column.
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/examples/nextjs-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "react-jsx",
16 | "incremental": true,
17 | "plugins": [
18 | {
19 | "name": "next"
20 | }
21 | ],
22 | "paths": {
23 | "@/*": ["./*"]
24 | }
25 | },
26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
27 | "exclude": ["node_modules"]
28 | }
29 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/SplitButton/SplitButton.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js';
3 | import employeeIcon from '@ui5/webcomponents-icons/dist/employee.js';
4 | import { SplitButton } from './index.js';
5 |
6 | const meta = {
7 | title: 'Inputs / SplitButton',
8 | component: SplitButton,
9 | argTypes: {
10 | children: { control: { type: 'text' } },
11 | },
12 | args: {
13 | design: ButtonDesign.Default,
14 | icon: employeeIcon,
15 | children: 'SplitButton',
16 | },
17 | tags: ['package:@ui5/webcomponents'],
18 | } satisfies Meta;
19 |
20 | export default meta;
21 | type Story = StoryObj;
22 |
23 | export const Default: Story = {};
24 |
--------------------------------------------------------------------------------
/templates/nextjs-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "react-jsx",
16 | "incremental": true,
17 | "plugins": [
18 | {
19 | "name": "next"
20 | }
21 | ],
22 | "paths": {
23 | "@/*": ["./*"]
24 | }
25 | },
26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
27 | "exclude": ["node_modules"]
28 | }
29 |
--------------------------------------------------------------------------------
/packages/main/src/components/ResponsiveGridLayout/ResponsiveGridLayout.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './ResponsiveGridLayout.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/packages/charts/src/components/PieChart/Placeholder.tsx:
--------------------------------------------------------------------------------
1 | import { ThemingParameters } from '@ui5/webcomponents-react-base';
2 | import ContentLoader from 'react-content-loader';
3 |
4 | export const PieChartPlaceholder = (props) => {
5 | return (
6 | // @ts-expect-error: TypeScript is going crazy
7 |
18 |
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/templates/nextjs-app/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import './clientAssetsImport.ts';
2 | import '@ui5/webcomponents-react/styles.css';
3 | import './globals.css';
4 | import { ThemeProvider } from '@ui5/webcomponents-react';
5 |
6 | export default function RootLayout({ children }: { children: React.ReactNode }) {
7 | return (
8 |
9 |
10 |
19 |
20 |
21 |
22 | {children}
23 |
24 |
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/TitleBar/index.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactNode } from 'react';
2 | import { forwardRef, isValidElement } from 'react';
3 | import { Title } from '../../../webComponents/Title/index.js';
4 |
5 | const styles = {
6 | minHeight: '1.5rem',
7 | display: 'flex',
8 | alignItems: 'center',
9 | };
10 |
11 | export interface TitleBarProps {
12 | children: ReactNode;
13 | titleBarId: string;
14 | }
15 |
16 | export const TitleBar = forwardRef((props, ref) => {
17 | const { children, titleBarId } = props;
18 | return (
19 |
20 | {typeof children === 'string' &&
{children} }
21 | {isValidElement(children) && children}
22 |
23 | );
24 | });
25 |
26 | TitleBar.displayName = 'TitleBar';
27 |
--------------------------------------------------------------------------------
/packages/main/src/enums/FlexBoxAlignItems.ts:
--------------------------------------------------------------------------------
1 | export enum FlexBoxAlignItems {
2 | /**
3 | * Items are aligned toward the start of the flex-direction.
4 | * Note: Corresponds to `flex-start`.
5 | */
6 | Start = 'Start',
7 | /**
8 | * Items are centered.
9 | * Note: Corresponds to `center`.
10 | */
11 | Center = 'Center',
12 | /**
13 | * Items are aligned toward the end of the flex-direction.
14 | * Note: Corresponds to `flex-end`.
15 | */
16 | End = 'End',
17 | /**
18 | * Items are aligned by their baseline.
19 | * Note: Corresponds to `baseline`.
20 | */
21 | Baseline = 'Baseline',
22 | /**
23 | * Items are stretched to fill the container.
24 | * Note: Corresponds to `stretch`.
25 | */
26 | Stretch = 'Stretch',
27 | }
28 |
--------------------------------------------------------------------------------
/examples/vite-ts/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import globals from 'globals';
3 | import reactHooks from 'eslint-plugin-react-hooks';
4 | import reactRefresh from 'eslint-plugin-react-refresh';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | { ignores: ['dist'] },
9 | {
10 | extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 | files: ['**/*.{ts,tsx}'],
12 | languageOptions: {
13 | ecmaVersion: 2020,
14 | globals: globals.browser,
15 | },
16 | plugins: {
17 | 'react-hooks': reactHooks,
18 | 'react-refresh': reactRefresh,
19 | },
20 | rules: {
21 | ...reactHooks.configs.recommended.rules,
22 | 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
23 | },
24 | },
25 | );
26 |
--------------------------------------------------------------------------------
/templates/vite-ts/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import globals from 'globals';
3 | import reactHooks from 'eslint-plugin-react-hooks';
4 | import reactRefresh from 'eslint-plugin-react-refresh';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | { ignores: ['dist'] },
9 | {
10 | extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 | files: ['**/*.{ts,tsx}'],
12 | languageOptions: {
13 | ecmaVersion: 2020,
14 | globals: globals.browser,
15 | },
16 | plugins: {
17 | 'react-hooks': reactHooks,
18 | 'react-refresh': reactRefresh,
19 | },
20 | rules: {
21 | ...reactHooks.configs.recommended.rules,
22 | 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
23 | },
24 | },
25 | );
26 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/RadioButton/RadioButton.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './RadioButton.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | # More Examples
20 |
21 |
22 |
23 | ## RadioButton groups
24 |
25 | Group radio buttons by using the `name` prop.
26 |
27 |
28 |
29 |
30 |
31 |
32 | ## RadioButton states
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/examples/react-router-ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["**/*", "**/.server/**/*", "**/.client/**/*", ".react-router/types/**/*"],
3 | "compilerOptions": {
4 | "lib": ["DOM", "DOM.Iterable", "ES2022"],
5 | "types": ["@react-router/node", "vite/client"],
6 | "rootDirs": [".", "./.react-router/types"],
7 | "isolatedModules": true,
8 | "esModuleInterop": true,
9 | "jsx": "react-jsx",
10 | "module": "ESNext",
11 | "moduleResolution": "Bundler",
12 | "resolveJsonModule": true,
13 | "target": "ES2022",
14 | "strict": true,
15 | "allowJs": true,
16 | "skipLibCheck": true,
17 | "forceConsistentCasingInFileNames": true,
18 | "baseUrl": ".",
19 | "paths": {
20 | "~/*": ["./app/*"]
21 | },
22 |
23 | // Vite takes care of building everything, not tsc.
24 | "noEmit": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js';
2 | import reactHooks from 'eslint-plugin-react-hooks';
3 | import reactRefresh from 'eslint-plugin-react-refresh';
4 | import globals from 'globals';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | { ignores: ['dist'] },
9 | {
10 | extends: [js.configs.recommended, ...tseslint.configs.recommended],
11 | files: ['**/*.{ts,tsx}'],
12 | languageOptions: {
13 | ecmaVersion: 2020,
14 | globals: globals.browser,
15 | },
16 | plugins: {
17 | 'react-hooks': reactHooks,
18 | 'react-refresh': reactRefresh,
19 | },
20 | rules: {
21 | ...reactHooks.configs.recommended.rules,
22 | 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
23 | },
24 | },
25 | );
26 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-react/styles.css';
2 | import '../styles/globals.css';
3 | import '@ui5/webcomponents-react/dist/Assets.js';
4 | import { ThemeProvider } from '@ui5/webcomponents-react';
5 | import type { AppProps } from 'next/app';
6 | import Head from 'next/head';
7 |
8 | export default function App({ Component, pageProps }: AppProps) {
9 | return (
10 | <>
11 |
12 |
21 |
22 |
23 |
24 |
25 | >
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/templates/nextjs-pages/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-pages",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "eslint ."
10 | },
11 | "dependencies": {
12 | "@ui5/webcomponents": "2.17.0",
13 | "@ui5/webcomponents-base": "2.17.0",
14 | "@ui5/webcomponents-fiori": "2.17.0",
15 | "@ui5/webcomponents-react": "2.17.0",
16 | "@types/node": "24.10.4",
17 | "@types/react": "19.2.7",
18 | "@types/react-dom": "19.2.3",
19 | "eslint": "9.39.2",
20 | "eslint-config-next": "16.0.10",
21 | "next": "16.0.10",
22 | "react": "19.2.3",
23 | "react-dom": "19.2.3",
24 | "typescript": "5.9.3"
25 | },
26 | "overrides": {
27 | "@types/react": "19.2.7",
28 | "@types/react-dom": "19.2.3"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/charts/src/resources/NormalizedStackedChart.mdx:
--------------------------------------------------------------------------------
1 | import { Canvas } from '@storybook/addon-docs/blocks';
2 |
3 | ### Normalized stacked chart
4 |
5 | By transforming the `dataset`, a stacked chart can be normalized.
6 |
7 |
8 |
9 | #### Example normalize function
10 |
11 | ```ts
12 | function normalizeData(data: Record[]) {
13 | return data.map((item) => {
14 | const total = Object.values(item).reduce((acc: number, cur) => {
15 | return typeof cur === 'number' ? acc + cur : acc;
16 | }, 0);
17 |
18 | const normalizedItem = Object.entries(item).map(([key, val]) => {
19 | if (typeof val === 'number') {
20 | return [key, total ? (val / total) * 100 : 0];
21 | }
22 | return [key, val];
23 | });
24 |
25 | return Object.fromEntries(normalizedItem);
26 | });
27 | }
28 | ```
29 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.base.json",
3 | "references": [
4 | {
5 | "path": "./packages/base/tsconfig.json"
6 | },
7 | {
8 | "path": "./packages/main/tsconfig.json"
9 | },
10 | {
11 | "path": "./packages/charts/tsconfig.json"
12 | },
13 | {
14 | "path": "./packages/cypress-commands/tsconfig.json"
15 | },
16 | {
17 | "path": "./packages/cli/tsconfig.json"
18 | },
19 | {
20 | "path": "./packages/compat/tsconfig.json"
21 | },
22 | {
23 | "path": "./packages/ai/tsconfig.json"
24 | },
25 | {
26 | "path": "./tsconfig.spec.json"
27 | },
28 | {
29 | "path": "./.storybook/tsconfig.json"
30 | },
31 | {
32 | "path": "./tsconfig.node.json"
33 | }
34 | ],
35 | "files": ["vite.config.ts", "types.d.ts"],
36 | "include": ["docs"]
37 | }
38 |
--------------------------------------------------------------------------------
/packages/charts/src/hooks/useLegendItemClick.ts:
--------------------------------------------------------------------------------
1 | import { enrichEventWithDetails } from '@ui5/webcomponents-react-base';
2 | import { useCallback } from 'react';
3 |
4 | export const useLegendItemClick = (handler, dataKeyExtractor?) => {
5 | return useCallback(
6 | (payload, index, event) => {
7 | if (typeof handler === 'function') {
8 | const dataKeyExtractorInternal = typeof dataKeyExtractor === 'function' ? dataKeyExtractor : (e?) => e?.dataKey;
9 | handler(
10 | enrichEventWithDetails(event, {
11 | dataKey: dataKeyExtractorInternal(payload),
12 | value: payload.value,
13 | chartType: payload.type,
14 | color: payload.color,
15 | payload: payload.payload,
16 | index,
17 | }),
18 | );
19 | }
20 | },
21 | [handler, dataKeyExtractor],
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/packages/cli/src/util/cem-reader.ts:
--------------------------------------------------------------------------------
1 | import { readFileSync } from 'node:fs';
2 | import { createRequire } from 'node:module';
3 | import type * as CEM from '@ui5/webcomponents-tools/lib/cem/types.js';
4 |
5 | const cache = new Map();
6 |
7 | export function getCEM(packageName: string) {
8 | if (!cache.has(packageName)) {
9 | const require = createRequire(import.meta.url);
10 | const customElementManifestPath = require.resolve(`${packageName}/dist/custom-elements-internal.json`);
11 |
12 | const customElementManifest: CEM.Package = JSON.parse(
13 | readFileSync(customElementManifestPath, { encoding: 'utf-8' }),
14 | );
15 | cache.set(packageName, customElementManifest);
16 | }
17 |
18 | const cem = cache.get(packageName);
19 | if (!cem) {
20 | throw new Error(`Could not load CEM for ${packageName}`);
21 | }
22 | return cem;
23 | }
24 |
--------------------------------------------------------------------------------
/.github/workflows/open-source-security.yml:
--------------------------------------------------------------------------------
1 | name: Open Source Security
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | schedule:
8 | - cron: '12 3 * * *'
9 | workflow_dispatch:
10 |
11 | jobs:
12 | piper-oss:
13 | name: 'Security'
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
17 |
18 | - name: artifactPrepareVersion
19 | uses: SAP/project-piper-action@f5707cddbf1ed8a72adbfad43a677bbfb7fd6ac9 # v1.25.1
20 | with:
21 | step-name: artifactPrepareVersion
22 | flags: --versioningType cloud_noTag
23 |
24 | - name: detectExecuteScan
25 | uses: SAP/project-piper-action@f5707cddbf1ed8a72adbfad43a677bbfb7fd6ac9 # v1.25.1
26 | with:
27 | step-name: detectExecuteScan
28 | flags: '--token ${{ secrets.DETECT_TOKEN }}'
29 |
--------------------------------------------------------------------------------
/docs/knowledgeBaseExamples/slotExamples.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Bar, Button } from '@ui5/webcomponents-react';
3 |
4 | const FaultyBarStart = () => {
5 | return Start
;
6 | };
7 | const FaultyBarEnd = () => {
8 | return Close ;
9 | };
10 | export const FaultyBarComponent = () => {
11 | return (
12 | } endContent={ }>
13 | Not a custom component
14 |
15 | );
16 | };
17 |
18 | const BarStart = (props) => {
19 | return Start
;
20 | };
21 | const BarEnd = (props) => {
22 | return Close ;
23 | };
24 | export const BarComponent = () => {
25 | return (
26 | } endContent={ }>
27 | Not a custom component
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/examples/nextjs-app/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-react/styles.css';
2 | import './globals.css';
3 | import { AppShell } from '@/app/components/AppShell';
4 | import { ThemeProvider } from '@ui5/webcomponents-react';
5 |
6 | export default function RootLayout({ children }: { children: React.ReactNode }) {
7 | return (
8 |
9 |
10 |
19 |
20 |
21 |
22 |
23 | {children}
24 |
25 |
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/hooks/useFontsReady.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | // If reused, think about implementing the behavior via useSyncExternalStore
4 |
5 | /**
6 | * Hook that returns whether the fonts are loaded and ready to use.
7 | *
8 | * @returns boolean
9 | */
10 | export function useFontsReady(): boolean {
11 | const [fontsReady, setFontsReady] = useState(document.fonts?.status === 'loaded');
12 | useEffect(() => {
13 | if (!document.fonts) {
14 | return;
15 | }
16 |
17 | if (document.fonts.status === 'loading') {
18 | let mounted = true;
19 |
20 | void document.fonts.ready.then(() => {
21 | if (mounted) {
22 | setFontsReady(true);
23 | }
24 | });
25 |
26 | return () => {
27 | mounted = false;
28 | };
29 | }
30 | }, []);
31 |
32 | return fontsReady;
33 | }
34 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Avatar/Avatar.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import AvatarColorScheme from '@ui5/webcomponents/dist/types/AvatarColorScheme.js';
3 | import AvatarShape from '@ui5/webcomponents/dist/types/AvatarShape.js';
4 | import AvatarSize from '@ui5/webcomponents/dist/types/AvatarSize.js';
5 | import { Avatar } from './index';
6 |
7 | const meta = {
8 | title: 'Data Display / Avatar',
9 | component: Avatar,
10 | argTypes: {
11 | children: { control: { disable: true } },
12 | },
13 | args: {
14 | colorScheme: AvatarColorScheme.Accent6,
15 | icon: 'employee',
16 | shape: AvatarShape.Circle,
17 | size: AvatarSize.S,
18 | },
19 | tags: ['package:@ui5/webcomponents'],
20 | } satisfies Meta;
21 |
22 | export default meta;
23 | type Story = StoryObj;
24 |
25 | export const Default: Story = {};
26 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | import path, { dirname } from 'node:path';
2 | import { fileURLToPath } from 'node:url';
3 |
4 | const __filename = fileURLToPath(import.meta.url);
5 | const __dirname = dirname(__filename);
6 |
7 | const root = path.resolve(__dirname, '..');
8 | const PATHS = {
9 | root,
10 | build: path.join(root, 'build'),
11 | shared: path.join(root, 'shared'),
12 | temp: path.join(root, 'temp'),
13 | nodeModules: path.join(root, 'node_modules'),
14 | packages: path.join(root, 'packages'),
15 | ai: path.join(root, 'packages', 'ai'),
16 | base: path.join(root, 'packages', 'base'),
17 | charts: path.join(root, 'packages', 'charts'),
18 | cli: path.join(root, 'packages', 'cli'),
19 | compat: path.join(root, 'packages', 'compat'),
20 | 'cypress-commands': path.join(root, 'packages', 'cypress-commands'),
21 | main: path.join(root, 'packages', 'main'),
22 | };
23 |
24 | export default PATHS;
25 |
--------------------------------------------------------------------------------
/.storybook/components/Footer.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | container: footer / inline-size;
3 | width: 100%;
4 | position: fixed;
5 | bottom: 0;
6 | z-index: 2;
7 | }
8 |
9 | .content {
10 | min-height: 2.75rem;
11 | padding-inline: 1rem;
12 | display: flex;
13 | align-items: center;
14 | background-color: var(--sapPageFooter_Background);
15 | border-top: 0.0625rem solid var(--sapPageFooter_BorderColor);
16 | overflow: hidden;
17 | }
18 |
19 | @container (max-width: 599px) {
20 | .footer {
21 | padding-inline: 1rem;
22 | }
23 | }
24 |
25 | @container (min-width: 600px) and (max-width: 1023px) {
26 | .footer {
27 | padding-inline: 2rem;
28 | }
29 | }
30 |
31 | @container (min-width: 1024px) and (max-width: 1439px) {
32 | .footer {
33 | padding-inline: 2rem;
34 | }
35 | }
36 |
37 | @container (min-width: 1440px) {
38 | .footer {
39 | padding-inline: 3rem;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/packages/compat/src/index.ts:
--------------------------------------------------------------------------------
1 | import VersionInfo from './generated/VersionInfo.js';
2 |
3 | export * from './components/Loader/index.js';
4 | export * from './components/OverflowToolbarButton/index.js';
5 | export * from './components/OverflowToolbarToggleButton/index.js';
6 | export * from './components/Table/index.js';
7 | export * from './components/TableCell/index.js';
8 | export * from './components/TableColumn/index.js';
9 | export * from './components/TableGroupRow/index.js';
10 | export * from './components/TableRow/index.js';
11 | export * from './components/Toolbar/index.js';
12 | export * from './components/ToolbarSeparator/index.js';
13 | export * from './components/ToolbarSpacer/index.js';
14 |
15 | export { LoaderType } from './enums/LoaderType.js';
16 | export { ToolbarDesign } from './enums/ToolbarDesign.js';
17 | export { ToolbarStyle } from './enums/ToolbarStyle.js';
18 | export const version = VersionInfo.version;
19 |
--------------------------------------------------------------------------------
/docs/EmbeddedStackBlitz.tsx:
--------------------------------------------------------------------------------
1 | import sdk from '@stackblitz/sdk';
2 | import { useEffect, useRef } from 'react';
3 |
4 | interface EmbeddedStackBlitzProps {
5 | repoPath: string;
6 | }
7 |
8 | export function EmbeddedStackBlitz({ repoPath }: EmbeddedStackBlitzProps) {
9 | const containerRef = useRef(null);
10 |
11 | useEffect(() => {
12 | const container = containerRef.current;
13 | if (!container) {
14 | return;
15 | }
16 | sdk.embedGithubProject(container, repoPath, {
17 | openFile: 'src/App.tsx',
18 | view: 'editor',
19 | height: '90%',
20 | hideDevTools: true,
21 | terminalHeight: 0,
22 | });
23 |
24 | return () => {
25 | if (container) {
26 | container.innerHTML = '';
27 | }
28 | };
29 | }, [repoPath]);
30 |
31 | return
;
32 | }
33 |
34 | EmbeddedStackBlitz.displayName = 'EmbeddedStackBlitz';
35 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/ProductSwitch/ProductSwitch.mdx:
--------------------------------------------------------------------------------
1 | import { ArgTypesWithNote, ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import SubcomponentsSection from '@sb/docs/SubcomponentsSection.md?raw';
3 | import { Canvas, Description, Markdown, Meta } from '@storybook/addon-docs/blocks';
4 | import { ProductSwitchItem } from '../ProductSwitchItem';
5 | import * as ComponentStories from './ProductSwitch.stories';
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Example
14 |
15 |
16 |
17 | ## Properties
18 |
19 |
20 |
21 | {SubcomponentsSection}
22 |
23 | ## ProductSwitchItem
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/main/README.md:
--------------------------------------------------------------------------------
1 | # @ui5/webcomponents-react
2 |
3 | React components with Fiori compliant style by leveraging [UI5 Web Components](https://ui5.github.io/webcomponents/).
4 |
5 | ## Installation
6 |
7 | ```bash
8 | npm install @ui5/webcomponents-react
9 | ```
10 |
11 | ## Documentation
12 |
13 | You can find an interactive documentation in our [Storybook](https://ui5.github.io/webcomponents-react/).
14 |
15 | ## Contribute
16 |
17 | Please check our [Contribution Guidelines](https://github.com/UI5/webcomponents-react/blob/main/CONTRIBUTING.md).
18 |
19 | ## License
20 |
21 | Please see our [LICENSE](https://github.com/UI5/webcomponents-react/blob/main/LICENSE) for copyright and license information.
22 | Detailed information including third-party components and their licensing/copyright information is available via the [REUSE tool](https://api.reuse.software/info/github.com/UI5/webcomponents-react).
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.storybook/components/GitHub-Mark.tsx:
--------------------------------------------------------------------------------
1 | export const GitHubLogo = () => (
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/packages/main/src/components/Grid/Grid.module.css:
--------------------------------------------------------------------------------
1 | .grid {
2 | display: grid;
3 | grid-template-columns: repeat(12, 1fr);
4 | }
5 |
6 | .gridSpan1 {
7 | grid-column: span 1;
8 | }
9 |
10 | .gridSpan2 {
11 | grid-column: span 2;
12 | }
13 |
14 | .gridSpan3 {
15 | grid-column: span 3;
16 | }
17 |
18 | .gridSpan4 {
19 | grid-column: span 4;
20 | }
21 |
22 | .gridSpan5 {
23 | grid-column: span 5;
24 | }
25 |
26 | .gridSpan6 {
27 | grid-column: span 6;
28 | }
29 |
30 | .gridSpan7 {
31 | grid-column: span 7;
32 | }
33 |
34 | .gridSpan8 {
35 | grid-column: span 8;
36 | }
37 |
38 | .gridSpan9 {
39 | grid-column: span 9;
40 | }
41 |
42 | .gridSpan10 {
43 | grid-column: span 10;
44 | }
45 |
46 | .gridSpan11 {
47 | grid-column: span 11;
48 | }
49 |
50 | .gridSpan12 {
51 | grid-column: span 12;
52 | }
53 |
54 | .positionCenter {
55 | margin-inline: auto;
56 | }
57 |
58 | .positionRight {
59 | margin-inline: auto 0;
60 | }
61 |
--------------------------------------------------------------------------------
/examples/nextjs-pages/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-react/dist/Assets.js';
2 | import '@ui5/webcomponents-react/styles.css';
3 | import '../styles/globals.css';
4 | import { ThemeProvider } from '@ui5/webcomponents-react';
5 | import type { AppProps } from 'next/app';
6 | import Head from 'next/head';
7 | import { AppShell } from '../components/AppShell';
8 |
9 | export default function App({ Component, pageProps }: AppProps) {
10 | return (
11 | <>
12 |
13 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | >
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/packages/main/scripts/create-enum-export.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 | import PATHS from '../../../config/paths.js';
4 |
5 | const ENUMS_DIR = path.resolve(PATHS.packages, 'main', 'src', 'enums');
6 | const INTERNAL_COMPONENTS = ['GrowingMode', 'index'];
7 |
8 | const enums = fs
9 | .readdirSync(ENUMS_DIR)
10 | .filter((file) => fs.statSync(`${ENUMS_DIR}/${file}`).isFile())
11 | .map((file) => path.basename(file, '.ts'))
12 | // filter internal components
13 | .filter((file) => !INTERNAL_COMPONENTS.includes(file));
14 |
15 | let fileContent = `// This is an autogenerated file, please do not modify this file manually.
16 | // In case you added a new file to the /enums folder, please rerun the scripts/create-enum-export.js script.
17 |
18 | `;
19 |
20 | fileContent += enums.map((file) => `export * from './${file}.js';`).join('\n');
21 |
22 | fs.writeFileSync(path.join(PATHS.packages, 'main', 'src', 'enums', 'index.ts'), fileContent);
23 |
--------------------------------------------------------------------------------
/packages/main/src/enums/FlexBoxJustifyContent.ts:
--------------------------------------------------------------------------------
1 | export enum FlexBoxJustifyContent {
2 | /**
3 | * Items are aligned toward the start of the flex-direction.
4 | * Note: Corresponds to `flex-start`.
5 | */
6 | Start = 'Start',
7 | /**
8 | * Items are centered.
9 | * Note: Corresponds to `center`.
10 | */
11 | Center = 'Center',
12 | /**
13 | * Items are aligned toward the end of the flex-direction.
14 | * Note: Corresponds to `flex-end`.
15 | */
16 | End = 'End',
17 | /**
18 | * Items are evenly distributed on the main-axis with equal space around them.
19 | * Note: Corresponds to `space-around`.
20 | */
21 | SpaceAround = 'SpaceAround',
22 | /**
23 | * Items are evenly distributed on the main-axis; first item is on the start line, last item on the end line.
24 | * Note: Corresponds to `space-between`.
25 | */
26 | SpaceBetween = 'SpaceBetween',
27 | }
28 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/SegmentedButton/SegmentedButton.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import { SegmentedButtonItem } from '../SegmentedButtonItem/index.js';
3 | import { SegmentedButton } from './index.js';
4 |
5 | const meta = {
6 | title: 'Inputs / SegmentedButton',
7 | component: SegmentedButton,
8 | argTypes: {
9 | children: { control: { disable: true } },
10 | },
11 | args: {
12 | accessibleName: 'Segmented Button Example',
13 | children: (
14 | <>
15 | Button 1
16 | Button 2
17 | Button 3
18 | >
19 | ),
20 | },
21 | tags: ['package:@ui5/webcomponents'],
22 | } satisfies Meta;
23 |
24 | export default meta;
25 | type Story = StoryObj;
26 |
27 | export const Default: Story = {};
28 |
--------------------------------------------------------------------------------
/packages/main/src/components/NumericSideIndicator/NumericSideIndicator.module.css:
--------------------------------------------------------------------------------
1 | .numericSideIndicator {
2 | font-family: var(--sapFontFamily);
3 | font-size: var(--sapFontSmallSize);
4 | color: var(--sapTile_TextColor);
5 | display: flex;
6 | flex-direction: column;
7 | align-items: flex-end;
8 | min-width: 0;
9 | position: relative;
10 | }
11 |
12 | .title {
13 | text-align: end;
14 | text-overflow: ellipsis;
15 | overflow: hidden;
16 | padding-bottom: 0.25rem;
17 | max-width: 100%;
18 | }
19 |
20 | .value {
21 | font-size: inherit;
22 | color: inherit;
23 | white-space: pre-line;
24 | word-wrap: break-word;
25 | word-break: break-word;
26 | }
27 |
28 | .stateGood {
29 | color: var(--sapPositiveTextColor);
30 | }
31 |
32 | .stateError {
33 | color: var(--sapNegativeTextColor);
34 | }
35 |
36 | .stateCritical {
37 | color: var(--sapCriticalTextColor);
38 | }
39 |
40 | .stateNeutral {
41 | color: var(--sapNeutralTextColor);
42 | }
43 |
--------------------------------------------------------------------------------
/docs/knowledge-base/SsrLimitations.tsx:
--------------------------------------------------------------------------------
1 | import MessageStripDesign from '@ui5/webcomponents/dist/types/MessageStripDesign.js';
2 | import { MessageStrip } from '@ui5/webcomponents-react';
3 |
4 | export function SsrLimitations() {
5 | return (
6 |
7 | <>
8 | Known Limitations
9 |
10 |
11 | As custom elements need to be defined on the client, UI5 Web Components for React is only rendering the
12 | outer markup of the UI5 Web Component on the server. The rendering of the Web Component is still happening
13 | on the client.
14 |
15 |
16 | The Next.js app directory shows some hydration warnings on the client. These warnings seem not
17 | to affect the runtime.
18 |
19 |
20 | >
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/IllustratedMessage/IllustratedMessage.stories.tsx:
--------------------------------------------------------------------------------
1 | import '@ui5/webcomponents-fiori/dist/illustrations/AllIllustrations.js';
2 | import type { Meta, StoryObj } from '@storybook/react-vite';
3 | import IllustrationMessageType from '@ui5/webcomponents-fiori/dist/types/IllustrationMessageType.js';
4 | import { IllustratedMessage } from './index';
5 |
6 | const meta = {
7 | title: 'User Feedback / IllustratedMessage',
8 | component: IllustratedMessage,
9 | args: {
10 | name: IllustrationMessageType.BeforeSearch,
11 | },
12 | argTypes: {
13 | children: { control: false },
14 | subtitle: { control: false },
15 | name: {
16 | control: 'select',
17 | options: Object.values(IllustrationMessageType),
18 | },
19 | },
20 | tags: ['package:@ui5/webcomponents'],
21 | } satisfies Meta;
22 |
23 | export default meta;
24 | type Story = StoryObj;
25 |
26 | export const Default: Story = {};
27 |
--------------------------------------------------------------------------------
/packages/charts/src/hooks/useCancelAnimationFallback.ts:
--------------------------------------------------------------------------------
1 | import { debounce } from '@ui5/webcomponents-react-base';
2 | import { useRef, useState } from 'react';
3 |
4 | export const useCancelAnimationFallback = (
5 | noAnimation: boolean,
6 | ): { isMounted: boolean; handleBarAnimationStart: () => void; handleBarAnimationEnd: () => void } => {
7 | const [isMounted, setIsMounted] = useState(true);
8 | const cancelAnimationFallback = () => {
9 | setIsMounted(false);
10 | setIsMounted(true);
11 | };
12 | const debouncedCancelAnimationFallback = useRef(debounce(cancelAnimationFallback, 1500)).current;
13 |
14 | const handleBarAnimationStart = () => {
15 | if (!noAnimation) {
16 | debouncedCancelAnimationFallback();
17 | }
18 | };
19 | const handleBarAnimationEnd = () => {
20 | if (!noAnimation) {
21 | debouncedCancelAnimationFallback.cancel();
22 | }
23 | };
24 | return { isMounted, handleBarAnimationStart, handleBarAnimationEnd };
25 | };
26 |
--------------------------------------------------------------------------------
/.storybook/components/DocsHeader.module.css:
--------------------------------------------------------------------------------
1 | .infoTable {
2 | margin: 1rem 0;
3 | border-spacing: 0;
4 | width: unset;
5 | }
6 |
7 | .infoTable th,
8 | .infoTable td {
9 | margin-top: 0;
10 | margin-bottom: 0.75rem;
11 | text-align: start;
12 | height: 1.5rem;
13 | }
14 |
15 | .infoTable th {
16 | padding-inline-end: 1.25rem;
17 | vertical-align: baseline;
18 | }
19 |
20 | .copyBtn {
21 | position: absolute;
22 | top: 4px;
23 | right: 8px;
24 | display: none;
25 | }
26 |
27 | .hoverTr {
28 | position: relative;
29 | }
30 |
31 | .hoverTr:hover .copyBtn {
32 | display: inline-block;
33 | }
34 |
35 | .infoTable td[data-import-cell='true'] {
36 | padding-inline-end: 2.5rem;
37 | }
38 |
39 | .titleRow {
40 | padding-block-end: 0.5rem;
41 | }
42 |
43 | .titleRow :global(.sbdocs-title) {
44 | margin-bottom: 0;
45 | }
46 |
47 | .experimentalLabel {
48 | font-size: var(--sapObjectHeader_Title_SnappedFontSize);
49 | margin-inline-start: 0.25rem;
50 | align-self: flex-end;
51 | }
52 |
--------------------------------------------------------------------------------
/templates/vite-ts/README.md:
--------------------------------------------------------------------------------
1 | # UI5 Web Components for React - Vite + TypeScript Template
2 |
3 | ## How to use this template
4 |
5 | ```bash
6 | npx degit UI5/webcomponents-react/templates/vite-ts#main my-project
7 | cd my-project
8 | ```
9 |
10 | ## Getting Started
11 |
12 | First, install the `node_modules`:
13 |
14 | ```bash
15 | npm install
16 | ```
17 |
18 | Then, run the development server:
19 |
20 | ```bash
21 | npm run dev
22 | ```
23 |
24 | ## Run Tests
25 |
26 | Run all component tests headlessly in Chrome:
27 |
28 | ```bash
29 | npm run test
30 | ```
31 |
32 | Open component tests in Chrome:
33 |
34 | ```bash
35 | npm run test:open
36 | ```
37 |
38 | ## Learn More
39 |
40 | To learn more about Vite and UI5 Web Components for React, please visit the following resources:
41 |
42 | - [Vite Documentation](https://vitejs.dev/)
43 | - [UI5 Web Components Documentation](https://ui5.github.io/webcomponents/)
44 | - [UI5 Web Components for React Documentation](https://ui5.github.io/webcomponents-react/)
45 |
--------------------------------------------------------------------------------
/packages/main/src/components/AnalyticalTable/defaults/Column/Cell.tsx:
--------------------------------------------------------------------------------
1 | import type { CellInstance } from '../../types/index.js';
2 |
3 | export const Cell = (props: CellInstance) => {
4 | const {
5 | cell: { value = '', isGrouped },
6 | column,
7 | row,
8 | webComponentsReactProperties,
9 | } = props;
10 | let cellContent = `${value ?? ''}`;
11 | if (isGrouped) {
12 | cellContent += ` (${row.subRows.length})`;
13 | }
14 |
15 | return (
16 |
24 | {cellContent}
25 |
26 | );
27 | };
28 |
29 | Cell.displayName = 'CellContent';
30 |
--------------------------------------------------------------------------------
/patterns/navigation-layout/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "navigation-layout",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@ui5/webcomponents": "2.17.0",
14 | "@ui5/webcomponents-base": "2.17.0",
15 | "@ui5/webcomponents-fiori": "2.17.0",
16 | "@ui5/webcomponents-icons": "2.17.0",
17 | "@ui5/webcomponents-react": "2.17.0",
18 | "react": "19.2.3",
19 | "react-dom": "19.2.3"
20 | },
21 | "devDependencies": {
22 | "@types/react": "19.2.7",
23 | "@types/react-dom": "19.2.3",
24 | "@vitejs/plugin-react": "5.1.2",
25 | "eslint": "9.39.2",
26 | "eslint-plugin-react-hooks": "6.1.1",
27 | "eslint-plugin-react-refresh": "0.4.25",
28 | "globals": "16.5.0",
29 | "typescript": "5.8.3",
30 | "typescript-eslint": "8.49.0",
31 | "vite": "7.2.7"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/packages/base/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as Device from './Device/index.js';
2 | import VersionInfo from './generated/VersionInfo.js';
3 | import * as hooks from './hooks/index.js';
4 | import { I18nStore } from './internal/stores/I18nStore.js';
5 | import { StyleStore } from './internal/stores/StyleStore.js';
6 | import { withWebComponent } from './internal/wrapper/withWebComponent.js';
7 | import type { WithWebComponentPropTypes } from './internal/wrapper/withWebComponent.js';
8 | import { ThemingParameters } from './styling/ThemingParameters.js';
9 |
10 | export * from './internal/styling/CssSizeVariables.js';
11 | export * from './internal/utils/index.js';
12 | export * from './hooks/index.js';
13 | export * from './internal/hooks/index.js';
14 | export type * from './internal/types/index.js';
15 | export type * from './types/index.js';
16 |
17 | export { I18nStore, StyleStore, ThemingParameters, Device, hooks, withWebComponent };
18 | export type { WithWebComponentPropTypes };
19 | export const version = VersionInfo.version;
20 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/MessageStrip/MessageStrip.stories.tsx:
--------------------------------------------------------------------------------
1 | import type { Meta, StoryObj } from '@storybook/react-vite';
2 | import MessageStripDesign from '@ui5/webcomponents/dist/types/MessageStripDesign.js';
3 | import employeeIcon from '@ui5/webcomponents-icons/dist/employee.js';
4 | import { Icon } from '../Icon/index.js';
5 | import { MessageStrip } from './index.js';
6 |
7 | const meta = {
8 | title: 'Data Display / MessageStrip',
9 | component: MessageStrip,
10 | argTypes: {
11 | children: { control: 'text' },
12 | icon: { control: { disable: true } },
13 | },
14 | args: {
15 | design: MessageStripDesign.Information,
16 | children: 'MessageStrip Text',
17 | },
18 | tags: ['package:@ui5/webcomponents'],
19 | } satisfies Meta;
20 |
21 | export default meta;
22 | type Story = StoryObj;
23 |
24 | export const Default: Story = {};
25 |
26 | export const WithIcon: Story = {
27 | args: {
28 | icon: ,
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/examples/react-router-ts/README.md:
--------------------------------------------------------------------------------
1 | # UI5 Web Components React - React Router Example
2 |
3 | This example shows how to use the [React Router](https://reactrouter.com/) with UI5 Web Components for React.
4 | This example was previously known as [Remix](https://remix.run/), and got updated to use React Router v7.
5 |
6 | ## How to use this template
7 |
8 | ```bash
9 | npx degit UI5/webcomponents-react/examples/react-router-ts#main my-project
10 | cd my-project
11 | ```
12 |
13 | ## Getting Started
14 |
15 | First, install the node_modules:
16 |
17 | ```bash
18 | npm install
19 | ```
20 |
21 | Then, run the development server:
22 |
23 | ```bash
24 | npm run dev
25 | ```
26 |
27 | ## Deployment
28 |
29 | First, build your app for production:
30 |
31 | ```sh
32 | npm run build
33 | ```
34 |
35 | Then run the app in production mode:
36 |
37 | ```sh
38 | npm start
39 | ```
40 |
41 | Now you'll need to pick a host to deploy it to.
42 |
43 | ## Learn More
44 |
45 | - 📖 See the [React router docs](https://reactrouter.com/home).
46 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Breadcrumbs/Breadcrumbs.mdx:
--------------------------------------------------------------------------------
1 | import { ArgTypesWithNote, ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import SubcomponentsSection from '@sb/docs/SubcomponentsSection.md?raw';
3 | import { Canvas, Description, Markdown, Meta } from '@storybook/addon-docs/blocks';
4 | import { BreadcrumbsItem } from '../BreadcrumbsItem';
5 | import * as ComponentStories from './Breadcrumbs.stories';
6 | import { excludePropsForAbstract } from '@sb/utils';
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ## Example
15 |
16 |
17 |
18 | ## Properties
19 |
20 |
21 |
22 | {SubcomponentsSection}
23 |
24 | ## BreadcrumbsItem
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/packages/charts/src/components/ColumnChartWithTrend/ColumnChartWithTrend.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './ColumnChartWithTrend.stories';
4 | import LegendStory from '../../resources/LegendConfig.mdx';
5 | import TooltipStory from '../../resources/TooltipConfig.mdx';
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 |
16 |
17 | ### Loading Placeholder
18 |
19 |
20 |
21 | Note: The tooltipConfig is used for both LineChart and ColumnChart.>} />
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/packages/main/src/webComponents/Dialog/Dialog.mdx:
--------------------------------------------------------------------------------
1 | import { ControlsWithNote, DocsHeader, Footer } from '@sb/components';
2 | import { Canvas, Meta } from '@storybook/addon-docs/blocks';
3 | import * as ComponentStories from './Dialog.stories';
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## Example
12 |
13 |
14 |
15 | ## Properties
16 |
17 |
18 |
19 | ## Opening Dialogs
20 |
21 | You can open and close the `Dialog` component in a declarative way using the `open` prop.
22 |
23 | ```jsx
24 | const MyComponentWithDialog = () => {
25 | const [dialogIsOpen, setDialogIsOpen] = useState(false);
26 | return (
27 | <>
28 | {
30 | setDialogIsOpen(true);
31 | }}
32 | >
33 | Open Dialog
34 |
35 |
36 | >
37 | );
38 | };
39 | ```
40 |
41 |
42 |
--------------------------------------------------------------------------------