diff --git a/browser/package-lock.json b/browser/package-lock.json index 48ded16e3..a49e6e8b2 100644 --- a/browser/package-lock.json +++ b/browser/package-lock.json @@ -15,6 +15,8 @@ "classnames": "2.3.1", "dompurify": "^3.3.0", "file-saver": "1.3.8", + "igniteui-dockmanager": "^1.17.0", + "igniteui-grid-lite": "^1.0.0-alpha.9", "igniteui-react": "^19.4.0-rc.0", "igniteui-react-charts": "19.3.0-beta.0", "igniteui-react-core": "19.3.0-beta.0", @@ -7958,6 +7960,36 @@ "igniteui-trial-watermark": "^1.0.3" } }, + "node_modules/igniteui-grid-lite": { + "version": "1.0.0-alpha.9", + "resolved": "https://registry.npmjs.org/igniteui-grid-lite/-/igniteui-grid-lite-1.0.0-alpha.9.tgz", + "integrity": "sha512-LxyUDHf/lTTbAAupup8HovSKsy1qgTUp4btrWVRQDFq2HI2s75UroplNGSX1yLfy3VCMEf8xY0sciM2tyFgzQQ==", + "license": "MIT", + "dependencies": { + "@lit-labs/virtualizer": "~2.1.0", + "@lit/context": "~1.1.5", + "igniteui-webcomponents": "~6.1.0", + "lit": "^3.3.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/igniteui-grid-lite/node_modules/igniteui-webcomponents": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/igniteui-webcomponents/-/igniteui-webcomponents-6.1.2.tgz", + "integrity": "sha512-q3a3Q28xzRwDBmfDprY0PsN9cs5xgqOJigXWWmbWAfcMgPg5dIrPyMDV6Aj6GD7u1RgPeoZmTP/pz9gTWNhHJA==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@floating-ui/dom": "^1.7.0", + "@lit-labs/virtualizer": "^2.1.0", + "@lit/context": "^1.1.0", + "lit": "^3.3.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/igniteui-react": { "version": "19.4.0-rc.0", "resolved": "https://registry.npmjs.org/igniteui-react/-/igniteui-react-19.4.0-rc.0.tgz", diff --git a/browser/package.json b/browser/package.json index 92533c38b..cfb696e13 100644 --- a/browser/package.json +++ b/browser/package.json @@ -23,6 +23,8 @@ "classnames": "2.3.1", "dompurify": "^3.3.0", "file-saver": "1.3.8", + "igniteui-dockmanager": "^1.17.0", + "igniteui-grid-lite": "^1.0.0-alpha.9", "igniteui-react": "^19.4.0-rc.0", "igniteui-react-charts": "19.3.0-beta.0", "igniteui-react-core": "19.3.0-beta.0", diff --git a/browser/public/meta.json b/browser/public/meta.json index c071e16e1..042142baa 100644 --- a/browser/public/meta.json +++ b/browser/public/meta.json @@ -1 +1 @@ -{"version":"23.2.915","date":"2025-11-14 14:29:21","note":"this file is auto-generated"} +{"version":"23.2.915","date":"2025-11-24 10:34:52","note":"this file is auto-generated"} \ No newline at end of file diff --git a/browser/src/navigation/SamplesBrowser.json b/browser/src/navigation/SamplesBrowser.json index 55577491b..042142baa 100644 --- a/browser/src/navigation/SamplesBrowser.json +++ b/browser/src/navigation/SamplesBrowser.json @@ -1 +1 @@ -{"version":"23.2.915","date":"2025-11-14 15:39:37","note":"this file is auto-generated"} +{"version":"23.2.915","date":"2025-11-24 10:34:52","note":"this file is auto-generated"} \ No newline at end of file diff --git a/browser/src/typedecls.d.ts b/browser/src/typedecls.d.ts new file mode 100644 index 000000000..0423e4419 --- /dev/null +++ b/browser/src/typedecls.d.ts @@ -0,0 +1,12 @@ +/* tslint:disable */ +declare module JSX { + interface IntrinsicElements { + "igc-grid-lite": any; + "igc-avatar": any; + "igc-rating": any; + "igc-checkbox": any; + "igc-select": any; + "igc-select-item": any; + } + } + /* tslint:enable */ \ No newline at end of file diff --git a/samples/charts/data-chart/user-annotation-layer/ReadMe.md b/samples/charts/data-chart/user-annotation-layer/ReadMe.md index 311717f82..6560b02b4 100644 --- a/samples/charts/data-chart/user-annotation-layer/ReadMe.md +++ b/samples/charts/data-chart/user-annotation-layer/ReadMe.md @@ -1,7 +1,7 @@ -This folder contains implementation of React application with example of Actions Built In Data Chart feature using [Toolbar](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. +This folder contains implementation of React application with example of User Annotation Layer feature using [Data Chart](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. @@ -12,10 +12,10 @@ This folder contains implementation of React application with example of Actions View Code - + Run Sample - + Run Sample @@ -34,7 +34,7 @@ Follow these instructions to run this example: git clone https://github.com/IgniteUI/igniteui-react-examples.git git checkout master cd ./igniteui-react-examples -cd ./samples/charts/toolbar/actions-built-in-data-chart +cd ./samples/charts/data-chart/user-annotation-layer ``` open above folder in VS Code or type: diff --git a/samples/grids/grid-lite/column-config-basic/.eslintrc.js b/samples/grids/grid-lite/column-config-basic/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-basic/ReadMe.md b/samples/grids/grid-lite/column-config-basic/ReadMe.md new file mode 100644 index 000000000..d8e264b92 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Column Config Basic feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/column-config-basic +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/column-config-basic/index.html b/samples/grids/grid-lite/column-config-basic/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-basic/package.json b/samples/grids/grid-lite/column-config-basic/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/column-config-basic/sandbox.config.json b/samples/grids/grid-lite/column-config-basic/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-basic/src/GridLiteDataService.ts b/samples/grids/grid-lite/column-config-basic/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-basic/src/index.css b/samples/grids/grid-lite/column-config-basic/src/index.css new file mode 100644 index 000000000..4a470efda --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/src/index.css @@ -0,0 +1,9 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-basic/src/index.tsx b/samples/grids/grid-lite/column-config-basic/src/index.tsx new file mode 100644 index 000000000..2aadabba0 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/src/index.tsx @@ -0,0 +1,99 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, ProductInfo } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent +} from 'igniteui-webcomponents'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcRatingComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private formatter: Intl.NumberFormat; + private gridRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.formatter = new Intl.NumberFormat('en-EN', { + style: 'currency', + currency: 'EUR' + }); + this.gridRef = React.createRef(); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: ProductInfo[] = this.dataService.generateProducts(50); + + const columns = [ + { + key: 'name', + headerText: 'Product Name' + }, + { + key: 'price', + headerText: 'Price', + type: 'number', + cellTemplate: (params: any) => { + const span = document.createElement('span'); + span.textContent = this.formatter.format(params.value); + return span; + } + }, + { + key: 'sold', + type: 'number', + headerText: 'Units sold' + }, + { + key: 'total', + headerText: 'Total sold', + cellTemplate: (params: any) => { + const span = document.createElement('span'); + span.textContent = this.formatter.format(params.value); + return span; + } + }, + { + key: 'rating', + type: 'number', + headerText: 'Customer rating', + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('step', '0.01'); + rating.setAttribute('value', params.value.toString()); + return rating; + } + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/column-config-basic/tsconfig.json b/samples/grids/grid-lite/column-config-basic/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/column-config-basic/vite.config.js b/samples/grids/grid-lite/column-config-basic/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/column-config-basic/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-dynamic/.eslintrc.js b/samples/grids/grid-lite/column-config-dynamic/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-dynamic/ReadMe.md b/samples/grids/grid-lite/column-config-dynamic/ReadMe.md new file mode 100644 index 000000000..9a174f74b --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Column Config Dynamic feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/column-config-dynamic +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/column-config-dynamic/index.html b/samples/grids/grid-lite/column-config-dynamic/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-dynamic/package.json b/samples/grids/grid-lite/column-config-dynamic/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/column-config-dynamic/sandbox.config.json b/samples/grids/grid-lite/column-config-dynamic/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-dynamic/src/GridLiteDataService.ts b/samples/grids/grid-lite/column-config-dynamic/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-dynamic/src/index.css b/samples/grids/grid-lite/column-config-dynamic/src/index.css new file mode 100644 index 000000000..41b27aca7 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/src/index.css @@ -0,0 +1,38 @@ +#panel { + margin: 1rem 0; + display: flex; + flex-flow: row nowrap; + justify-content: space-between; + align-items: center; +} + +.config-key { + flex: 2 1 25% !important; + font-weight: bold; +} + +.config { + display: flex; + flex-flow: row nowrap; + justify-content: space-evenly; + align-items: center; + gap: 0.75rem; +} + +.config * { + flex: 1; +} + +igc-dropdown-item { + padding: 0.5rem 1rem; +} + +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-dynamic/src/index.tsx b/samples/grids/grid-lite/column-config-dynamic/src/index.tsx new file mode 100644 index 000000000..a146f4cc9 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/src/index.tsx @@ -0,0 +1,142 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, ProductInfo } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent +} from 'igniteui-webcomponents'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcRatingComponent); + +const formatter = new Intl.NumberFormat('en-EN', { + style: 'currency', + currency: 'EUR', +}); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + protected hasFormatters = true; + protected format = (params: any) => { + const span = document.createElement('span'); + span.textContent = formatter.format(params.value); + return span; + }; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.toggleFormatters = this.toggleFormatters.bind(this); + this.toggleColumnProperty = this.toggleColumnProperty.bind(this); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: ProductInfo[] = this.dataService.generateProducts(50); + + const columns = [ + { + key: 'id', + hidden: true, + headerText: 'ID' + }, + { + key: 'name', + headerText: 'Product Name' + }, + { + key: 'price', + headerText: 'Price', + type: 'number', + cellTemplate: this.format + }, + { + key: 'sold', + type: 'number', + headerText: 'Units sold' + }, + { + key: 'total', + headerText: 'Total sold', + cellTemplate: this.format + }, + { + key: 'rating', + type: 'number', + headerText: 'Customer rating', + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('step', '0.01'); + rating.setAttribute('value', params.value.toString()); + return rating; + } + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + toggleFormatters(checked: boolean) { + if (this.gridRef.current) { + this.gridRef.current.updateColumns( + ['price', 'total'].map((key) => ({ + key, + cellTemplate: checked ? this.format : undefined, + })) + ); + } + } + + toggleColumnProperty(columnKey: string, property: string, value: boolean) { + if (this.gridRef.current) { + this.gridRef.current.updateColumns({ key: columnKey, [property]: value }); + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+

Column Properties (simplified controls):

+ + + +
+
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/column-config-dynamic/tsconfig.json b/samples/grids/grid-lite/column-config-dynamic/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/column-config-dynamic/vite.config.js b/samples/grids/grid-lite/column-config-dynamic/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/column-config-dynamic/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-headers/.eslintrc.js b/samples/grids/grid-lite/column-config-headers/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-headers/ReadMe copy.md b/samples/grids/grid-lite/column-config-headers/ReadMe copy.md new file mode 100644 index 000000000..c3201cc22 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/ReadMe copy.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Toolbar Sample3 feature using [Grid](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid/toolbar-sample-3 +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/column-config-headers/ReadMe.md b/samples/grids/grid-lite/column-config-headers/ReadMe.md new file mode 100644 index 000000000..28e6b48b3 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Column Config Headers feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/column-config-headers +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/column-config-headers/index.html b/samples/grids/grid-lite/column-config-headers/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-headers/package.json b/samples/grids/grid-lite/column-config-headers/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/column-config-headers/sandbox.config.json b/samples/grids/grid-lite/column-config-headers/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-headers/src/GridLiteDataService.ts b/samples/grids/grid-lite/column-config-headers/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-headers/src/index.css b/samples/grids/grid-lite/column-config-headers/src/index.css new file mode 100644 index 000000000..2079f4e88 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/src/index.css @@ -0,0 +1,9 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/column-config-headers/src/index.tsx b/samples/grids/grid-lite/column-config-headers/src/index.tsx new file mode 100644 index 000000000..76cd0ff18 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/src/index.tsx @@ -0,0 +1,71 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, User } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: User[] = this.dataService.generateUsers(50); + + const columns = [ + { + key: 'id', + headerText: '🆔 ID', + width: '150px' + }, + { + key: 'firstName', + headerText: '👤 First Name' + }, + { + key: 'lastName', + headerText: '👤 Last Name' + }, + { + key: 'age', + headerText: '🎂 Age', + type: 'number', + width: '100px' + }, + { + key: 'email', + headerText: '📧 Email' + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/column-config-headers/tsconfig.json b/samples/grids/grid-lite/column-config-headers/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/column-config-headers/vite.config.js b/samples/grids/grid-lite/column-config-headers/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/column-config-headers/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/data-binding/.eslintrc.js b/samples/grids/grid-lite/data-binding/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/data-binding/ReadMe.md b/samples/grids/grid-lite/data-binding/ReadMe.md new file mode 100644 index 000000000..ac7302ece --- /dev/null +++ b/samples/grids/grid-lite/data-binding/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Data Binding feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/data-binding +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/data-binding/index.html b/samples/grids/grid-lite/data-binding/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/data-binding/package.json b/samples/grids/grid-lite/data-binding/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/data-binding/sandbox.config.json b/samples/grids/grid-lite/data-binding/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/data-binding/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/data-binding/src/GridLiteDataService.ts b/samples/grids/grid-lite/data-binding/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/data-binding/src/index.css b/samples/grids/grid-lite/data-binding/src/index.css new file mode 100644 index 000000000..329ffb098 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/src/index.css @@ -0,0 +1,34 @@ +.controls-wrapper { + margin-bottom: 1rem; + display: flex; + gap: 0.5rem; + align-items: center; +} + +.sample-button { + padding: 0.5rem 1rem; + cursor: pointer; + background-color: #007bff; + color: white; + border: none; + border-radius: 4px; +} + +.sample-button:hover { + background-color: #0056b3; +} + +.record-count { + font-weight: bold; + margin-left: 1rem; +} + +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} diff --git a/samples/grids/grid-lite/data-binding/src/index.tsx b/samples/grids/grid-lite/data-binding/src/index.tsx new file mode 100644 index 000000000..9f2e6e052 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/src/index.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcButtonComponent +} from 'igniteui-webcomponents'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcButtonComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + private showingProducts = true; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.switchData = this.switchData.bind(this); + } + + componentDidMount() { + if (this.gridRef.current) { + this.gridRef.current.data = this.dataService.generateProducts(50); + + window.addEventListener('error', (e) => { + if (e.message === 'ResizeObserver loop completed with undelivered notifications.') { + e.stopImmediatePropagation(); + } + }); + } + } + + private switchData() { + if (this.gridRef.current) { + this.gridRef.current.columns = []; + + if (this.showingProducts) { + this.gridRef.current.data = this.dataService.generateUsers(50); + this.showingProducts = false; + } else { + this.gridRef.current.data = this.dataService.generateProducts(50); + this.showingProducts = true; + } + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/data-binding/tsconfig.json b/samples/grids/grid-lite/data-binding/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/data-binding/vite.config.js b/samples/grids/grid-lite/data-binding/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/data-binding/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-events/.eslintrc.js b/samples/grids/grid-lite/filtering-config-events/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-events/ReadMe.md b/samples/grids/grid-lite/filtering-config-events/ReadMe.md new file mode 100644 index 000000000..851b905f4 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Filtering Config Events feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/filtering-config-events +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/filtering-config-events/index.html b/samples/grids/grid-lite/filtering-config-events/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-events/package.json b/samples/grids/grid-lite/filtering-config-events/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/filtering-config-events/sandbox.config.json b/samples/grids/grid-lite/filtering-config-events/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-events/src/GridLiteDataService.ts b/samples/grids/grid-lite/filtering-config-events/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-events/src/index.css b/samples/grids/grid-lite/filtering-config-events/src/index.css new file mode 100644 index 000000000..6cf15a462 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/src/index.css @@ -0,0 +1,27 @@ +.grid-lite-wrapper { + width: 100%; + height: calc(100% - 10rem); +} + +igc-grid-lite { + min-height: 65vh; +} + +.log { + margin-top: 0.5rem; + border: 1px solid #ccc; + padding: 1rem; + min-height: 1rem; + font-size: 0.75rem; + max-height: 5rem; + overflow-y: auto; +} + +.log p { + margin: 0.25rem 0; +} + +.log code { + font-family: monospace; + font-size: 0.75rem; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-events/src/index.tsx b/samples/grids/grid-lite/filtering-config-events/src/index.tsx new file mode 100644 index 000000000..017e0332e --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/src/index.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, User } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + private logRef: React.RefObject; + private log: string[] = []; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.logRef = React.createRef(); + this.state = { logContent: '' }; + } + + get time() { + return `[${new Date().toLocaleTimeString()}]`; + } + + componentDidMount() { + if (this.gridRef.current) { + const data: User[] = this.dataService.generateUsers(50); + + const columns = [ + { key: 'firstName', headerText: 'First name', filter: true }, + { key: 'lastName', headerText: 'Last name', filter: true }, + { key: 'age', headerText: 'Age', filter: true, type: 'number' }, + { key: 'email', headerText: 'Email', filter: true } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + + // Listen to filter events + this.gridRef.current.addEventListener('filtering', (e: any) => { + const { expressions, type } = e.detail; + this.updateLog(`${this.time} :: Event \`${e.type}\` :: Filter operation of type '${type}' for column '${expressions[0].key}'`); + }); + this.gridRef.current.addEventListener('filtered', (e: any) => { + this.updateLog(`${this.time} :: Event \`${e.type}\` for column '${e.detail.key}'`); + }); + } + } + + private updateLog(message: string) { + if (this.log.length > 10) { + this.log.shift(); + } + this.log.push(message); + this.renderLog(); + } + + private renderLog() { + const logContent = this.log + .map(entry => `

${entry}

`) + .join(''); + this.setState({ logContent }); + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/filtering-config-events/tsconfig.json b/samples/grids/grid-lite/filtering-config-events/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/filtering-config-events/vite.config.js b/samples/grids/grid-lite/filtering-config-events/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-events/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-remote/.eslintrc.js b/samples/grids/grid-lite/filtering-config-remote/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-remote/ReadMe.md b/samples/grids/grid-lite/filtering-config-remote/ReadMe.md new file mode 100644 index 000000000..609cf70fa --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Filtering Config Remote feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/filtering-config-remote +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/filtering-config-remote/index.html b/samples/grids/grid-lite/filtering-config-remote/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-remote/package.json b/samples/grids/grid-lite/filtering-config-remote/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/filtering-config-remote/sandbox.config.json b/samples/grids/grid-lite/filtering-config-remote/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-remote/src/GridLiteDataService.ts b/samples/grids/grid-lite/filtering-config-remote/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-remote/src/index.css b/samples/grids/grid-lite/filtering-config-remote/src/index.css new file mode 100644 index 000000000..a04c50eec --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/src/index.css @@ -0,0 +1,30 @@ +p { + border: 1px solid var(--border); + padding: 1rem; + min-height: 1rem; + font-size: 0.75rem; +} + +code { + background-color: rgba(0, 0, 0, 0.05); + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 4px; + padding: 0.125rem 0.375rem; + font-family: 'Courier New', Courier, monospace; + font-size: 0.875em; + color: #222222; + display: inline-block; + width: 100%; + min-height: 2em; + box-sizing: border-box; +} + +.grid-lite-wrapper { + width: 100%; + height: calc(100% - 1rem); +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config-remote/src/index.tsx b/samples/grids/grid-lite/filtering-config-remote/src/index.tsx new file mode 100644 index 000000000..590f05b85 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/src/index.tsx @@ -0,0 +1,100 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, User } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); + +function groupBy(arr: T[], key: keyof T) { + const out: Record = {}; + for (const each of arr) { + const slot = each[key] as string; + if (!out[slot]) { + out[slot] = []; + } + out[slot].push(each); + } + return out; +} + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + private allData: User[] = []; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.allData = this.dataService.generateUsers(100); + this.state = { queryString: '' }; + } + + componentDidMount() { + if (this.gridRef.current) { + const columns = [ + { key: 'firstName', headerText: 'First name', filter: true }, + { key: 'lastName', headerText: 'Last name', filter: true }, + { key: 'age', headerText: 'Age', filter: true, type: 'number' }, + { key: 'email', headerText: 'Email' } + ]; + + const config = { + filter: async ({ data, grid }: any) => { + this.buildUri(grid.filterExpressions); + await new Promise((resolve) => setTimeout(resolve, 250)); + return data; + }, + }; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = this.allData; + this.gridRef.current.dataPipelineConfiguration = config; + } + } + + protected mapExpressions(arr: any[]) { + return arr + .map(({ searchTerm, criteria, condition }: any, idx: number) => { + const c = condition; + return idx < 1 + ? `${c.name}("${searchTerm}")` + : `${criteria?.toUpperCase()} ${c.name}("${searchTerm}")`; + }) + .join(' '); + } + + protected buildUri(state: any[]) { + const out: string[] = []; + const qs = groupBy(state, 'key'); + for (const [key, exprs] of Object.entries(qs)) { + out.push(`${key}(${this.mapExpressions(exprs)})`); + } + this.setState({ queryString: `GET: /data?filter=${out.join('&')}` }); + } + + public render(): JSX.Element { + return ( +
+
+
+ {this.state.queryString} +
+
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/filtering-config-remote/tsconfig.json b/samples/grids/grid-lite/filtering-config-remote/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/filtering-config-remote/vite.config.js b/samples/grids/grid-lite/filtering-config-remote/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config-remote/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config/.eslintrc.js b/samples/grids/grid-lite/filtering-config/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config/ReadMe.md b/samples/grids/grid-lite/filtering-config/ReadMe.md new file mode 100644 index 000000000..7606d807a --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Filtering Config feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/filtering-config +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/filtering-config/index.html b/samples/grids/grid-lite/filtering-config/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config/package.json b/samples/grids/grid-lite/filtering-config/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/filtering-config/sandbox.config.json b/samples/grids/grid-lite/filtering-config/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config/src/GridLiteDataService.ts b/samples/grids/grid-lite/filtering-config/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config/src/index.css b/samples/grids/grid-lite/filtering-config/src/index.css new file mode 100644 index 000000000..2079f4e88 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/src/index.css @@ -0,0 +1,9 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/filtering-config/src/index.tsx b/samples/grids/grid-lite/filtering-config/src/index.tsx new file mode 100644 index 000000000..d4ad26d14 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/src/index.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, User } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcCheckboxComponent +} from 'igniteui-webcomponents'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcCheckboxComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: User[] = this.dataService.generateUsers(50); + + const columns = [ + { + key: 'firstName', + headerText: 'First name', + filter: true + }, + { + key: 'lastName', + headerText: 'Last name', + filter: true + }, + { + key: 'age', + headerText: 'Age', + filter: true, + type: 'number' + }, + { + key: 'active', + headerText: 'Active', + type: 'boolean', + filter: true, + cellTemplate: (params: any) => { + const checkbox = document.createElement('igc-checkbox'); + if (params.value) { + checkbox.setAttribute('checked', ''); + } + return checkbox; + } + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/filtering-config/tsconfig.json b/samples/grids/grid-lite/filtering-config/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/filtering-config/vite.config.js b/samples/grids/grid-lite/filtering-config/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/filtering-config/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/overview/.eslintrc.js b/samples/grids/grid-lite/overview/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/overview/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/overview/ReadMe.md b/samples/grids/grid-lite/overview/ReadMe.md new file mode 100644 index 000000000..9d3f5fcf4 --- /dev/null +++ b/samples/grids/grid-lite/overview/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Overview feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/overview +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/overview/index.html b/samples/grids/grid-lite/overview/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/overview/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/overview/package.json b/samples/grids/grid-lite/overview/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/overview/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/overview/sandbox.config.json b/samples/grids/grid-lite/overview/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/overview/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/overview/src/GridLiteDataService.ts b/samples/grids/grid-lite/overview/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/overview/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/overview/src/index.css b/samples/grids/grid-lite/overview/src/index.css new file mode 100644 index 000000000..651829746 --- /dev/null +++ b/samples/grids/grid-lite/overview/src/index.css @@ -0,0 +1,9 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 75vh; + --ig-size: 1; +} diff --git a/samples/grids/grid-lite/overview/src/index.tsx b/samples/grids/grid-lite/overview/src/index.tsx new file mode 100644 index 000000000..5e3a342f4 --- /dev/null +++ b/samples/grids/grid-lite/overview/src/index.tsx @@ -0,0 +1,151 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, User } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent, + IgcCheckboxComponent, + IgcSelectComponent, + IgcAvatarComponent +} from 'igniteui-webcomponents'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents( + IgcAvatarComponent, + IgcRatingComponent, + IgcCheckboxComponent, + IgcSelectComponent +); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private choices = ['Low', 'Standard', 'High']; + private gridRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: User[] = this.dataService.generateUsers(1000); + + const columns = [ + { + key: 'avatar', + headerText: 'Avatar', + cellTemplate: (params: any) => { + const cell = document.createElement('igc-avatar'); + cell.setAttribute('shape', 'circle'); + cell.setAttribute('alt', 'User avatar'); + cell.setAttribute('src', params.value); + return cell; + } + }, + { + key: 'firstName', + headerText: 'First name', + sort: true, + filter: true, + resizable: true + }, + { + key: 'lastName', + headerText: 'Last name', + sort: true, + filter: true, + resizable: true + }, + { + key: 'email', + headerText: 'Email Address' + }, + { + key: 'priority', + headerText: 'Priority', + width: '12rem', + sort: { + comparer: (a: string, b: string) => this.choices.indexOf(a) - this.choices.indexOf(b), + caseSensitive: true + }, + cellTemplate: (params: any) => { + const select = document.createElement('igc-select'); + select.setAttribute('outlined', ''); + select.setAttribute('flip', ''); + select.setAttribute('value', params.value); + + this.choices.forEach(choice => { + const item = document.createElement('igc-select-item'); + item.setAttribute('value', choice); + item.textContent = choice; + select.appendChild(item); + }); + + return select; + } + }, + { + key: 'satisfaction', + headerText: 'Satisfaction rating', + type: 'number', + sort: true, + filter: true, + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('value', params.value.toString()); + return rating; + } + }, + { + key: 'registeredAt', + headerText: 'Registered @', + sort: true, + cellTemplate: (params: any) => { + const span = document.createElement('span'); + span.textContent = params.value.toLocaleString(); + return span; + } + }, + { + key: 'active', + type: 'boolean', + headerText: 'Active', + cellTemplate: (params: any) => { + const checkbox = document.createElement('igc-checkbox'); + if (params.value) { + checkbox.setAttribute('checked', ''); + } + return checkbox; + } + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/overview/tsconfig.json b/samples/grids/grid-lite/overview/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/overview/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/overview/vite.config.js b/samples/grids/grid-lite/overview/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/overview/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-events/.eslintrc.js b/samples/grids/grid-lite/sort-config-events/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-events/ReadMe copy.md b/samples/grids/grid-lite/sort-config-events/ReadMe copy.md new file mode 100644 index 000000000..c3201cc22 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/ReadMe copy.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Toolbar Sample3 feature using [Grid](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid/toolbar-sample-3 +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/sort-config-events/ReadMe.md b/samples/grids/grid-lite/sort-config-events/ReadMe.md new file mode 100644 index 000000000..3c055bc87 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Sort Config Events feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/sort-config-events +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/sort-config-events/index.html b/samples/grids/grid-lite/sort-config-events/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-events/package.json b/samples/grids/grid-lite/sort-config-events/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/sort-config-events/sandbox.config.json b/samples/grids/grid-lite/sort-config-events/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-events/src/GridLiteDataService.ts b/samples/grids/grid-lite/sort-config-events/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-events/src/index.css b/samples/grids/grid-lite/sort-config-events/src/index.css new file mode 100644 index 000000000..6cf15a462 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/src/index.css @@ -0,0 +1,27 @@ +.grid-lite-wrapper { + width: 100%; + height: calc(100% - 10rem); +} + +igc-grid-lite { + min-height: 65vh; +} + +.log { + margin-top: 0.5rem; + border: 1px solid #ccc; + padding: 1rem; + min-height: 1rem; + font-size: 0.75rem; + max-height: 5rem; + overflow-y: auto; +} + +.log p { + margin: 0.25rem 0; +} + +.log code { + font-family: monospace; + font-size: 0.75rem; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-events/src/index.tsx b/samples/grids/grid-lite/sort-config-events/src/index.tsx new file mode 100644 index 000000000..108d11390 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/src/index.tsx @@ -0,0 +1,140 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, ProductInfo } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent +} from 'igniteui-webcomponents'; +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcRatingComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + private log: string[] = []; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.state = { logContent: '' }; + this.handleSorting = this.handleSorting.bind(this); + this.handleSorted = this.handleSorted.bind(this); + } + + get timeStamp(): string { + return `[${new Date().toLocaleTimeString()}]`; + } + + componentDidMount() { + if (this.gridRef.current) { + const data: ProductInfo[] = this.dataService.generateProducts(100); + + const columns = [ + { + key: 'name', + headerText: 'Name', + sort: true + }, + { + key: 'price', + type: 'number', + headerText: 'Price', + sort: true + }, + { + key: 'rating', + type: 'number', + headerText: 'Rating', + sort: true, + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('step', '0.01'); + rating.setAttribute('value', params.value.toString()); + return rating; + } + }, + { + key: 'sold', + type: 'number', + headerText: 'Sold', + sort: true + }, + { + key: 'total', + type: 'number', + headerText: 'Total', + sort: true + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + + // Listen to sorting events + this.gridRef.current.addEventListener('sorting', this.handleSorting); + this.gridRef.current.addEventListener('sorted', this.handleSorted); + } + } + + private updateLog(message: string) { + if (this.log.length > 10) { + this.log.shift(); + } + this.log.push(message); + this.renderLog(); + } + + private renderLog() { + const logContent = this.log + .map(entry => `

${entry}

`) + .join(''); + this.setState({ logContent }); + } + + private handleSorting(event: any) { + const { detail, type } = event; + const allowedColumns = ['price', 'total', 'sold']; + + if (!allowedColumns.includes(detail.key)) { + event.preventDefault(); + this.updateLog( + `${this.timeStamp} :: Event '${type}' :: Sort operation was prevented for column '${detail.key}'` + ); + } else { + this.updateLog( + `${this.timeStamp} :: Event '${type}' :: Column '${detail.key}' is being sorted with expression: ${JSON.stringify(detail)}` + ); + } + } + + private handleSorted(event: any) { + const { detail, type } = event; + this.updateLog( + `${this.timeStamp} :: Event '${type}' :: Column '${detail.key}' was sorted with expression: ${JSON.stringify(detail)}` + ); + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/sort-config-events/tsconfig.json b/samples/grids/grid-lite/sort-config-events/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/sort-config-events/vite.config.js b/samples/grids/grid-lite/sort-config-events/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-events/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-grid/.eslintrc.js b/samples/grids/grid-lite/sort-config-grid/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-grid/ReadMe copy.md b/samples/grids/grid-lite/sort-config-grid/ReadMe copy.md new file mode 100644 index 000000000..c3201cc22 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/ReadMe copy.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Toolbar Sample3 feature using [Grid](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid/toolbar-sample-3 +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/sort-config-grid/ReadMe.md b/samples/grids/grid-lite/sort-config-grid/ReadMe.md new file mode 100644 index 000000000..2ce7eb028 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Sort Config Grid feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/sort-config-grid +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/sort-config-grid/index.html b/samples/grids/grid-lite/sort-config-grid/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-grid/package.json b/samples/grids/grid-lite/sort-config-grid/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/sort-config-grid/sandbox.config.json b/samples/grids/grid-lite/sort-config-grid/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-grid/src/GridLiteDataService.ts b/samples/grids/grid-lite/sort-config-grid/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-grid/src/index.css b/samples/grids/grid-lite/sort-config-grid/src/index.css new file mode 100644 index 000000000..0ab8179b9 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/src/index.css @@ -0,0 +1,14 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +.config-panel { + margin: 1rem 0; + display: flex; + gap: 2rem; +} + +igc-grid-lite { + height: 510px; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-grid/src/index.tsx b/samples/grids/grid-lite/sort-config-grid/src/index.tsx new file mode 100644 index 000000000..2f86ec854 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/src/index.tsx @@ -0,0 +1,113 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, ProductInfo } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent, + IgcSwitchComponent +} from 'igniteui-webcomponents'; +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcRatingComponent, IgcSwitchComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + private sortConfiguration: any = { + multiple: true, + triState: true + }; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.updateConfig = this.updateConfig.bind(this); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: ProductInfo[] = this.dataService.generateProducts(100); + + const columns = [ + { + key: 'name', + headerText: 'Name', + sort: true + }, + { + key: 'price', + type: 'number', + headerText: 'Price', + sort: true + }, + { + key: 'rating', + type: 'number', + headerText: 'Rating', + sort: true, + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('step', '0.01'); + rating.setAttribute('value', params.value.toString()); + return rating; + } + }, + { + key: 'sold', + type: 'number', + headerText: 'Sold', + sort: true + }, + { + key: 'total', + type: 'number', + headerText: 'Total', + sort: true + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + this.gridRef.current.sortConfiguration = this.sortConfiguration; + } + } + + private updateConfig(prop: string, checked: boolean) { + this.sortConfiguration = { ...this.sortConfiguration, [prop]: checked }; + if (this.gridRef.current) { + this.gridRef.current.sortConfiguration = this.sortConfiguration; + } + } + + public render(): JSX.Element { + return ( +
+
+ + +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/sort-config-grid/tsconfig.json b/samples/grids/grid-lite/sort-config-grid/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/sort-config-grid/vite.config.js b/samples/grids/grid-lite/sort-config-grid/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-grid/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-pipeline/.eslintrc.js b/samples/grids/grid-lite/sort-config-pipeline/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-pipeline/ReadMe.md b/samples/grids/grid-lite/sort-config-pipeline/ReadMe.md new file mode 100644 index 000000000..299a9fe00 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Sort Config Pipeline feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/sort-config-pipeline +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/sort-config-pipeline/index.html b/samples/grids/grid-lite/sort-config-pipeline/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-pipeline/package.json b/samples/grids/grid-lite/sort-config-pipeline/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/sort-config-pipeline/sandbox.config.json b/samples/grids/grid-lite/sort-config-pipeline/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-pipeline/src/GridLiteDataService.ts b/samples/grids/grid-lite/sort-config-pipeline/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-pipeline/src/index.css b/samples/grids/grid-lite/sort-config-pipeline/src/index.css new file mode 100644 index 000000000..3c9d8e570 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/src/index.css @@ -0,0 +1,37 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +.grid-section { + position: relative; +} + +igc-circular-progress { + visibility: hidden; + --diameter: 4rem; + background-color: rgba(255, 255, 255, 0.5); + position: absolute; + z-index: 2; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.in-operation { + visibility: visible; + pointer-events: all; + user-select: contain; +} + +p { + border: 1px solid #ccc; + padding: 1rem; + min-height: 1rem; + font-size: 0.75rem; +} + +igc-grid-lite { + min-height: 65vh; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-pipeline/src/index.tsx b/samples/grids/grid-lite/sort-config-pipeline/src/index.tsx new file mode 100644 index 000000000..09beead12 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/src/index.tsx @@ -0,0 +1,135 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, ProductInfo } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent, + IgcCircularProgressComponent +} from 'igniteui-webcomponents'; +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcRatingComponent, IgcCircularProgressComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + private progressRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + this.progressRef = React.createRef(); + this.state = { queryString: '' }; + } + + componentDidMount() { + if (this.gridRef.current) { + const data: ProductInfo[] = this.dataService.generateProducts(100); + + const columns = [ + { + key: 'name', + headerText: 'Name', + sort: true + }, + { + key: 'price', + type: 'number', + headerText: 'Price', + sort: true + }, + { + key: 'rating', + type: 'number', + headerText: 'Rating', + sort: true, + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('step', '0.01'); + rating.setAttribute('value', params.value.toString()); + return rating; + } + }, + { + key: 'sold', + type: 'number', + headerText: 'Sold', + sort: true + }, + { + key: 'total', + type: 'number', + headerText: 'Total', + sort: true + } + ]; + + const dataPipelineConfiguration = { + sort: async ({ data, grid }: any) => { + if (this.progressRef.current) { + this.progressRef.current.classList.add('in-operation'); + } + const queryString = grid.sortExpressions.length + ? this.buildUri(grid.sortExpressions) + : ''; + this.setState({ queryString }); + + await new Promise(resolve => setTimeout(resolve, 250)); + if (this.progressRef.current) { + this.progressRef.current.classList.remove('in-operation'); + } + return data; + } + }; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + this.gridRef.current.dataPipelineConfiguration = dataPipelineConfiguration; + } + } + + private buildUri(state: any[]): string { + const uri: string[] = []; + for (const expr of state) { + if (expr.direction === 'none') { + continue; + } + uri.push( + expr.direction === 'ascending' + ? `asc(${expr.key})` + : `desc(${expr.key})` + ); + } + return `GET: /data?sort_by=${uri.join(',')}`; + } + + public render(): JSX.Element { + return ( +
+
+
+ +
+
+ {this.state.queryString} +
+
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/sort-config-pipeline/tsconfig.json b/samples/grids/grid-lite/sort-config-pipeline/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/sort-config-pipeline/vite.config.js b/samples/grids/grid-lite/sort-config-pipeline/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-pipeline/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-sample/.eslintrc.js b/samples/grids/grid-lite/sort-config-sample/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-sample/ReadMe.md b/samples/grids/grid-lite/sort-config-sample/ReadMe.md new file mode 100644 index 000000000..9378f9196 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Sort Config Sample feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/sort-config-sample +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/sort-config-sample/index.html b/samples/grids/grid-lite/sort-config-sample/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-sample/package.json b/samples/grids/grid-lite/sort-config-sample/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/sort-config-sample/sandbox.config.json b/samples/grids/grid-lite/sort-config-sample/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-sample/src/GridLiteDataService.ts b/samples/grids/grid-lite/sort-config-sample/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-sample/src/index.css b/samples/grids/grid-lite/sort-config-sample/src/index.css new file mode 100644 index 000000000..2079f4e88 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/src/index.css @@ -0,0 +1,9 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +igc-grid-lite { + min-height: 65vh; + --ig-size: 2; +} \ No newline at end of file diff --git a/samples/grids/grid-lite/sort-config-sample/src/index.tsx b/samples/grids/grid-lite/sort-config-sample/src/index.tsx new file mode 100644 index 000000000..c2953a766 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/src/index.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, User } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: User[] = this.dataService.generateUsers(50); + + const columns = [ + { + key: 'firstName', + headerText: 'First name', + sort: true + }, + { + key: 'lastName', + headerText: 'Last name', + sort: true + }, + { + key: 'age', + headerText: 'Age', + sort: true, + type: 'number' + }, + { + key: 'email', + headerText: 'Email', + sort: true + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/sort-config-sample/tsconfig.json b/samples/grids/grid-lite/sort-config-sample/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/sort-config-sample/vite.config.js b/samples/grids/grid-lite/sort-config-sample/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/sort-config-sample/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file diff --git a/samples/grids/grid-lite/styling-custom-theme/.eslintrc.js b/samples/grids/grid-lite/styling-custom-theme/.eslintrc.js new file mode 100644 index 000000000..7168b7144 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/.eslintrc.js @@ -0,0 +1,78 @@ +// https://www.robertcooper.me/using-eslint-and-prettier-in-a-typescript-project +module.exports = { + parser: "@typescript-eslint/parser", // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: "module", // Allows for the use of imports + ecmaFeatures: { + jsx: true // Allows for the parsing of JSX + } + }, + settings: { + react: { + version: "999.999.999" // Tells eslint-plugin-react to automatically detect the version of React to use + } + }, + extends: [ + "eslint:recommended", + "plugin:react/recommended", // Uses the recommended rules from @eslint-plugin-react + "plugin:@typescript-eslint/recommended" // Uses the recommended rules from @typescript-eslint/eslint-plugin + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-prototype-builtins": "off", + "no-mixed-spaces-and-tabs": 0, + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "default-case": "off", + "jsx-a11y/alt-text": "off", + "jsx-a11y/iframe-has-title": "off", + "no-var": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-extend-native": "off", + "no-throw-literal": "off", + "no-useless-concat": "off", + "no-mixed-operators": "off", + "no-mixed-spaces-and-tabs": 0, + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/prefer-namespace-keyword": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ] + }; \ No newline at end of file diff --git a/samples/grids/grid-lite/styling-custom-theme/ReadMe.md b/samples/grids/grid-lite/styling-custom-theme/ReadMe.md new file mode 100644 index 000000000..625be1b94 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of React application with example of Styling Custom Theme feature using [Grid Lite](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-react-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-react-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +Follow these instructions to run this example: + + +``` +git clone https://github.com/IgniteUI/igniteui-react-examples.git +git checkout master +cd ./igniteui-react-examples +cd ./samples/grids/grid-lite/styling-custom-theme +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: +``` +npm install --legacy-peer-deps +npm run-script start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for React** components, check out the [React documentation](https://www.infragistics.com/products/ignite-ui-react/react/components/general-getting-started.html). diff --git a/samples/grids/grid-lite/styling-custom-theme/index.html b/samples/grids/grid-lite/styling-custom-theme/index.html new file mode 100644 index 000000000..fd8d08d53 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/index.html @@ -0,0 +1,12 @@ + + + + Sample | Ignite UI | React | infragistics + + + + +
+ + + \ No newline at end of file diff --git a/samples/grids/grid-lite/styling-custom-theme/package.json b/samples/grids/grid-lite/styling-custom-theme/package.json new file mode 100644 index 000000000..1fb4f5e31 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/package.json @@ -0,0 +1,49 @@ +{ + "name": "example-ignite-ui-react", + "description": "This project provides example of using Ignite UI for React components", + "author": "Infragistics", + "version": "1.4.0", + "license": "", + "homepage": ".", + "private": true, + "scripts": { + "start": "vite --port 4200", + "build": "tsc && node --max-old-space-size=4096 node_modules/vite/bin/vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint ./src/**/*.{ts,tsx}" + }, + "dependencies": { + "igniteui-dockmanager": "^1.17.0", + "igniteui-react": "^19.3.0", + "igniteui-react-core": "19.3.0-beta.0", + "igniteui-react-grids": "^19.3.0", + "igniteui-webcomponents": "^6.3.0", + "lit-html": "^3.2.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "@types/node": "^24.7.1", + "@types/react": "^18.0.24", + "@types/react-dom": "^18.0.8", + "@vitejs/plugin-react": "^5.0.4", + "@vitest/browser": "^3.2.4", + "eslint": "^8.33.0", + "eslint-config-react": "^1.1.7", + "eslint-plugin-react": "^7.20.0", + "typescript": "^4.8.4", + "vite": "^7.1.9", + "vitest": "^3.2.4", + "vitest-canvas-mock": "^0.3.3", + "worker-loader": "^3.0.8" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/samples/grids/grid-lite/styling-custom-theme/sandbox.config.json b/samples/grids/grid-lite/styling-custom-theme/sandbox.config.json new file mode 100644 index 000000000..07f53508e --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/sandbox.config.json @@ -0,0 +1,5 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser" +} \ No newline at end of file diff --git a/samples/grids/grid-lite/styling-custom-theme/src/GridLiteDataService.ts b/samples/grids/grid-lite/styling-custom-theme/src/GridLiteDataService.ts new file mode 100644 index 000000000..aa34be2d5 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/src/GridLiteDataService.ts @@ -0,0 +1,122 @@ +export type UserSimple = { + id: string; + username: string; + email: string; + subscribed: boolean; +}; + +export type ProductInfo = { + id: string; + name: string; + price: number; + sold: number; + rating: number; + total: number; +}; + +export type User = { + id: string; + firstName: string; + lastName: string; + age: number; + email: string; + avatar: string; + active: boolean; + priority: 'Low' | 'Standard' | 'High'; + satisfaction: number; + registeredAt: Date; +}; + +export class GridLiteDataService { + private counter = 0; + + private firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry', + 'Ivy', 'Jack', 'Kate', 'Liam', 'Mia', 'Noah', 'Olivia', 'Peter', 'Quinn', 'Rachel']; + private lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', + 'Rodriguez', 'Martinez', 'Wilson', 'Anderson', 'Taylor', 'Thomas', 'Moore', 'Jackson', 'White', 'Harris']; + private productNames = ['Widget', 'Gadget', 'Doohickey', 'Thingamajig', 'Gizmo', 'Contraption', + 'Device', 'Tool', 'Apparatus', 'Instrument', 'Machine', 'Equipment']; + private priorities: ('Low' | 'Standard' | 'High')[] = ['Low', 'Standard', 'High']; + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + private randomFloat(min: number, max: number, precision = 2): number { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const random01 = array[0] / 2 ** 32; + return parseFloat((random01 * (max - min) + min).toFixed(precision)); + } + + private randomElement(array: T[]): T { + return array[this.randomInt(0, array.length - 1)]; + } + + private randomBoolean(): boolean { + const array = new Uint8Array(1); + window.crypto.getRandomValues(array); + return (array[0] & 1) === 0; + } + + private generateId(): string { + return `${Date.now()}-${this.counter++}-${this.randomInt(1000, 9999)}`; + } + + createProductInfo(): ProductInfo { + const price = this.randomFloat(50, 500, 2); + const sold = this.randomInt(10, 100); + const total = parseFloat((price * sold).toFixed(2)); + + return { + price, + sold, + total, + id: this.generateId(), + name: `${this.randomElement(this.productNames)} ${this.randomElement(['Pro', 'Plus', 'Max', 'Ultra', 'Mini', 'Lite'])}`, + rating: this.randomFloat(0, 5, 1) + }; + } + + createUserSimple(): UserSimple { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + return { + id: this.generateId(), + username: `${firstName.toLowerCase()}.${lastName.toLowerCase()}${this.randomInt(1, 99)}`, + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`, + subscribed: this.randomBoolean() + }; + } + + createUser(): User { + const firstName = this.randomElement(this.firstNames); + const lastName = this.randomElement(this.lastNames); + const email = `${firstName.toLowerCase()}.${lastName.toLowerCase()}@example.com`; + + return { + id: this.generateId(), + firstName, + lastName, + age: this.randomInt(18, 90), + email, + avatar: `https://i.pravatar.cc/150?img=${this.randomInt(1, 70)}`, + active: this.randomBoolean(), + priority: this.randomElement(this.priorities), + satisfaction: this.randomInt(0, 5), + registeredAt: new Date(Date.now() - this.randomInt(0, 365 * 24 * 60 * 60 * 1000)) + }; + } + + generateUsers(count: number): User[] { + return Array.from({ length: count }, () => this.createUser()); + } + + generateProducts(count: number): ProductInfo[] { + return Array.from({ length: count }, () => this.createProductInfo()); + } + + generateSimpleUsers(count: number): UserSimple[] { + return Array.from({ length: count }, () => this.createUserSimple()); + } +} \ No newline at end of file diff --git a/samples/grids/grid-lite/styling-custom-theme/src/index.css b/samples/grids/grid-lite/styling-custom-theme/src/index.css new file mode 100644 index 000000000..5532f1303 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/src/index.css @@ -0,0 +1,405 @@ +.grid-lite-wrapper { + width: 100%; + height: 100%; +} + +.custom-styled { + --content-background: hsla(var(--ig-gray-50), var(--ig-gray-a)); + --content-text-color: var(--ig-gray-50-contrast); + --header-background: hsla(var(--ig-surface-500), var(--ig-surface-a)); + --header-text-color: var(--ig-surface-500-contrast); + --header-border-width: 0.0625rem; + --header-border-style: solid; + --header-border-color: hsla(var(--ig-gray-400), 0.38); + --filtering-header-background: hsla(var(--ig-gray-50) 205deg, 92%, 13%, var(--ig-gray-a)); + --filtering-row-background: hsla(var(--ig-gray-50), var(--ig-gray-a)); + --filtering-row-text-color: var(--ig-gray-50-contrast); + --sorted-header-icon-color: hsla(var(--ig-primary-500), var(--ig-primary-a)); + --icon-color: "currentColor"; + --row-hover-background: hsla(var(--ig-gray-200), var(--ig-gray-a)); + --row-hover-text-color: var(--ig-gray-200-contrast); + --row-even-background: hsla(var(--ig-gray-50), var(--ig-gray-a)); + --row-even-text-color: var(--ig-gray-50-contrast); + --row-odd-background: hsla(var(--ig-gray-50), var(--ig-gray-a)); + --row-odd-text-color: var(--ig-gray-50-contrast); + --row-border-color: hsla(var(--ig-gray-300), 0.38); + --row-border-style: solid; + --row-border-width: 0.0625rem; + --cell-active-border-color: hsla(var(--ig-primary-500), var(--ig-primary-a)); + --grid-resize-line-color: hsla(var(--ig-primary-500), var(--ig-primary-a)); + --ig-font-family: "Merriweather Sans", sans-serif; + --ig-h1-font-family: var(--ig-font-family); + --ig-h1-font-size: 2.5rem; + --ig-h1-font-weight: 500; + --ig-h1-font-style: normal; + --ig-h1-line-height: 3rem; + --ig-h1-letter-spacing: -0.09375rem; + --ig-h1-text-transform: none; + --ig-h1-margin-top: 0; + --ig-h1-margin-bottom: 0.5rem; + --ig-h2-font-family: var(--ig-font-family); + --ig-h2-font-size: 2rem; + --ig-h2-font-weight: 500; + --ig-h2-font-style: normal; + --ig-h2-line-height: 2.4rem; + --ig-h2-letter-spacing: -0.03125rem; + --ig-h2-text-transform: none; + --ig-h2-margin-top: 0; + --ig-h2-margin-bottom: 0.5rem; + --ig-h3-font-family: var(--ig-font-family); + --ig-h3-font-size: 1.75rem; + --ig-h3-font-weight: 500; + --ig-h3-font-style: normal; + --ig-h3-line-height: 2.1rem; + --ig-h3-letter-spacing: 0; + --ig-h3-text-transform: none; + --ig-h3-margin-top: 0; + --ig-h3-margin-bottom: 0.5rem; + --ig-h4-font-family: var(--ig-font-family); + --ig-h4-font-size: 1.5rem; + --ig-h4-font-weight: 500; + --ig-h4-font-style: normal; + --ig-h4-line-height: 1.8rem; + --ig-h4-letter-spacing: 0.015625rem; + --ig-h4-text-transform: none; + --ig-h4-margin-top: 0; + --ig-h4-margin-bottom: 0.5rem; + --ig-h5-font-family: var(--ig-font-family); + --ig-h5-font-size: 1.25rem; + --ig-h5-font-weight: 500; + --ig-h5-font-style: normal; + --ig-h5-line-height: 1.5rem; + --ig-h5-letter-spacing: 0; + --ig-h5-text-transform: none; + --ig-h5-margin-top: 0; + --ig-h5-margin-bottom: 0.5rem; + --ig-h6-font-family: var(--ig-font-family); + --ig-h6-font-size: 1rem; + --ig-h6-font-weight: 500; + --ig-h6-font-style: normal; + --ig-h6-line-height: 1.2rem; + --ig-h6-letter-spacing: 0.009375rem; + --ig-h6-text-transform: none; + --ig-h6-margin-top: 0; + --ig-h6-margin-bottom: 0.5rem; + --ig-subtitle-1-font-family: var(--ig-font-family); + --ig-subtitle-1-font-size: 0.875rem; + --ig-subtitle-1-font-weight: 400; + --ig-subtitle-1-font-style: normal; + --ig-subtitle-1-line-height: 1.5rem; + --ig-subtitle-1-letter-spacing: 0.009375rem; + --ig-subtitle-1-text-transform: none; + --ig-subtitle-1-margin-top: 0; + --ig-subtitle-1-margin-bottom: 0; + --ig-subtitle-2-font-family: var(--ig-font-family); + --ig-subtitle-2-font-size: 0.9rem; + --ig-subtitle-2-font-weight: 400; + --ig-subtitle-2-font-style: normal; + --ig-subtitle-2-line-height: 1.35rem; + --ig-subtitle-2-letter-spacing: 0.00625rem; + --ig-subtitle-2-text-transform: none; + --ig-subtitle-2-margin-top: 0; + --ig-subtitle-2-margin-bottom: 0; + --ig-body-1-font-family: var(--ig-font-family); + --ig-body-1-font-size: 1rem; + --ig-body-1-font-weight: 400; + --ig-body-1-font-style: normal; + --ig-body-1-line-height: 1.5rem; + --ig-body-1-letter-spacing: 0.03125rem; + --ig-body-1-text-transform: none; + --ig-body-1-margin-top: 0; + --ig-body-1-margin-bottom: 0; + --ig-body-2-font-family: var(--ig-font-family); + --ig-body-2-font-size: 0.9rem; + --ig-body-2-font-weight: 400; + --ig-body-2-font-style: normal; + --ig-body-2-line-height: 1.5rem; + --ig-body-2-letter-spacing: 0.015625rem; + --ig-body-2-text-transform: none; + --ig-body-2-margin-top: 0; + --ig-body-2-margin-bottom: 0; + --ig-button-font-family: var(--ig-font-family); + --ig-button-font-size: 1rem; + --ig-button-font-weight: 500; + --ig-button-font-style: normal; + --ig-button-line-height: 1.5rem; + --ig-button-letter-spacing: 0.046875rem; + --ig-button-text-transform: none; + --ig-button-margin-top: 0; + --ig-button-margin-bottom: 0; + --ig-caption-font-family: var(--ig-font-family); + --ig-caption-font-size: 0.75rem; + --ig-caption-font-weight: 400; + --ig-caption-font-style: normal; + --ig-caption-line-height: 1rem; + --ig-caption-letter-spacing: 0.025rem; + --ig-caption-text-transform: none; + --ig-caption-margin-top: 0; + --ig-caption-margin-bottom: 0; + --ig-overline-font-family: var(--ig-font-family); + --ig-overline-font-size: 0.625rem; + --ig-overline-font-weight: 400; + --ig-overline-font-style: normal; + --ig-overline-line-height: 1rem; + --ig-overline-letter-spacing: 0.09375rem; + --ig-overline-text-transform: uppercase; + --ig-overline-margin-top: 0; + --ig-overline-margin-bottom: 0; + --ig-calendar-labels-font-family: var(--ig-font-family); + --ig-calendar-labels-font-size: 0.8125rem; + --ig-calendar-labels-font-weight: 400; + --ig-calendar-labels-font-style: normal; + --ig-calendar-labels-line-height: normal; + --ig-calendar-labels-letter-spacing: normal; + --ig-calendar-labels-text-transform: none; + --ig-calendar-labels-margin-top: 0; + --ig-calendar-labels-margin-bottom: 0; + --ig-primary-50-contrast: black; + --ig-primary-50: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.23), calc(var(--ig-primary-l) * 1.78); + --ig-primary-100-contrast: black; + --ig-primary-100: var(--ig-primary-h), calc(var(--ig-primary-s) * 0.8), calc(var(--ig-primary-l) * 1.66); + --ig-primary-200-contrast: black; + --ig-primary-200: var(--ig-primary-h), calc(var(--ig-primary-s) * 0.64), calc(var(--ig-primary-l) * 1.43); + --ig-primary-300-contrast: black; + --ig-primary-300: var(--ig-primary-h), calc(var(--ig-primary-s) * 0.73), calc(var(--ig-primary-l) * 1.19); + --ig-primary-400-contrast: black; + --ig-primary-400: var(--ig-primary-h), calc(var(--ig-primary-s) * 0.875), calc(var(--ig-primary-l) * 1.08); + --ig-primary-h: 56deg; + --ig-primary-s: 75%; + --ig-primary-l: 50%; + --ig-primary-a: 1; + --ig-primary-500-contrast: black; + --ig-primary-500: var(--ig-primary-h), calc(var(--ig-primary-s) * 1), calc(var(--ig-primary-l) * 1); + --ig-primary-600-contrast: black; + --ig-primary-600: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.26), calc(var(--ig-primary-l) * 0.89); + --ig-primary-700-contrast: black; + --ig-primary-700: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.52), calc(var(--ig-primary-l) * 0.81); + --ig-primary-800-contrast: black; + --ig-primary-800: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.5), calc(var(--ig-primary-l) * 0.73); + --ig-primary-900-contrast: black; + --ig-primary-900: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.34), calc(var(--ig-primary-l) * 0.64); + --ig-primary-A100-contrast: black; + --ig-primary-A100: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.23), calc(var(--ig-primary-l) * 1.34); + --ig-primary-A200-contrast: black; + --ig-primary-A200: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.22), calc(var(--ig-primary-l) * 1.16); + --ig-primary-A400-contrast: black; + --ig-primary-A400: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.23), calc(var(--ig-primary-l) * 0.91); + --ig-primary-A700-contrast: black; + --ig-primary-A700: var(--ig-primary-h), calc(var(--ig-primary-s) * 1.23), calc(var(--ig-primary-l) * 0.65); + --ig-secondary-50-contrast: black; + --ig-secondary-50: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.23), calc(var(--ig-secondary-l) * 1.78); + --ig-secondary-100-contrast: black; + --ig-secondary-100: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 0.8), calc(var(--ig-secondary-l) * 1.66); + --ig-secondary-200-contrast: black; + --ig-secondary-200: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 0.64), calc(var(--ig-secondary-l) * 1.43); + --ig-secondary-300-contrast: black; + --ig-secondary-300: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 0.73), calc(var(--ig-secondary-l) * 1.19); + --ig-secondary-400-contrast: black; + --ig-secondary-400: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 0.875), calc(var(--ig-secondary-l) * 1.08); + --ig-secondary-h: 15deg; + --ig-secondary-s: 55%; + --ig-secondary-l: 64%; + --ig-secondary-a: 1; + --ig-secondary-500-contrast: black; + --ig-secondary-500: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1), calc(var(--ig-secondary-l) * 1); + --ig-secondary-600-contrast: black; + --ig-secondary-600: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.26), calc(var(--ig-secondary-l) * 0.89); + --ig-secondary-700-contrast: black; + --ig-secondary-700: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.52), calc(var(--ig-secondary-l) * 0.81); + --ig-secondary-800-contrast: black; + --ig-secondary-800: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.5), calc(var(--ig-secondary-l) * 0.73); + --ig-secondary-900-contrast: white; + --ig-secondary-900: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.34), calc(var(--ig-secondary-l) * 0.64); + --ig-secondary-A100-contrast: black; + --ig-secondary-A100: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.23), calc(var(--ig-secondary-l) * 1.34); + --ig-secondary-A200-contrast: black; + --ig-secondary-A200: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.22), calc(var(--ig-secondary-l) * 1.16); + --ig-secondary-A400-contrast: black; + --ig-secondary-A400: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.23), calc(var(--ig-secondary-l) * 0.91); + --ig-secondary-A700-contrast: white; + --ig-secondary-A700: var(--ig-secondary-h), calc(var(--ig-secondary-s) * 1.23), calc(var(--ig-secondary-l) * 0.65); + --ig-gray-50-contrast: white; + --ig-gray-50: var(--ig-gray-h), var(--ig-gray-s), 13%; + --ig-gray-100-contrast: white; + --ig-gray-100: var(--ig-gray-h), var(--ig-gray-s), 26%; + --ig-gray-200-contrast: white; + --ig-gray-200: var(--ig-gray-h), var(--ig-gray-s), 38%; + --ig-gray-300-contrast: black; + --ig-gray-300: var(--ig-gray-h), var(--ig-gray-s), 54%; + --ig-gray-400-contrast: black; + --ig-gray-400: var(--ig-gray-h), var(--ig-gray-s), 62%; + --ig-gray-h: 205deg; + --ig-gray-s: 92%; + --ig-gray-l: 74%; + --ig-gray-a: 1; + --ig-gray-500-contrast: black; + --ig-gray-500: var(--ig-gray-h), var(--ig-gray-s), 74%; + --ig-gray-600-contrast: black; + --ig-gray-600: var(--ig-gray-h), var(--ig-gray-s), 88%; + --ig-gray-700-contrast: black; + --ig-gray-700: var(--ig-gray-h), var(--ig-gray-s), 93%; + --ig-gray-800-contrast: black; + --ig-gray-800: var(--ig-gray-h), var(--ig-gray-s), 96%; + --ig-gray-900-contrast: black; + --ig-gray-900: var(--ig-gray-h), var(--ig-gray-s), 98%; + --ig-surface-50-contrast: white; + --ig-surface-50: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.23), calc(var(--ig-surface-l) * 1.78); + --ig-surface-100-contrast: white; + --ig-surface-100: var(--ig-surface-h), calc(var(--ig-surface-s) * 0.8), calc(var(--ig-surface-l) * 1.66); + --ig-surface-200-contrast: white; + --ig-surface-200: var(--ig-surface-h), calc(var(--ig-surface-s) * 0.64), calc(var(--ig-surface-l) * 1.43); + --ig-surface-300-contrast: white; + --ig-surface-300: var(--ig-surface-h), calc(var(--ig-surface-s) * 0.73), calc(var(--ig-surface-l) * 1.19); + --ig-surface-400-contrast: white; + --ig-surface-400: var(--ig-surface-h), calc(var(--ig-surface-s) * 0.875), calc(var(--ig-surface-l) * 1.08); + --ig-surface-h: 216deg; + --ig-surface-s: 92%; + --ig-surface-l: 14%; + --ig-surface-a: 1; + --ig-surface-500-contrast: white; + --ig-surface-500: var(--ig-surface-h), calc(var(--ig-surface-s) * 1), calc(var(--ig-surface-l) * 1); + --ig-surface-600-contrast: white; + --ig-surface-600: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.26), calc(var(--ig-surface-l) * 0.89); + --ig-surface-700-contrast: white; + --ig-surface-700: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.52), calc(var(--ig-surface-l) * 0.81); + --ig-surface-800-contrast: white; + --ig-surface-800: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.5), calc(var(--ig-surface-l) * 0.73); + --ig-surface-900-contrast: white; + --ig-surface-900: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.34), calc(var(--ig-surface-l) * 0.64); + --ig-surface-A100-contrast: white; + --ig-surface-A100: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.23), calc(var(--ig-surface-l) * 1.34); + --ig-surface-A200-contrast: white; + --ig-surface-A200: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.22), calc(var(--ig-surface-l) * 1.16); + --ig-surface-A400-contrast: white; + --ig-surface-A400: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.23), calc(var(--ig-surface-l) * 0.91); + --ig-surface-A700-contrast: white; + --ig-surface-A700: var(--ig-surface-h), calc(var(--ig-surface-s) * 1.23), calc(var(--ig-surface-l) * 0.65); + --ig-info-50-contrast: black; + --ig-info-50: var(--ig-info-h), calc(var(--ig-info-s) * 1.23), calc(var(--ig-info-l) * 1.78); + --ig-info-100-contrast: black; + --ig-info-100: var(--ig-info-h), calc(var(--ig-info-s) * 0.8), calc(var(--ig-info-l) * 1.66); + --ig-info-200-contrast: black; + --ig-info-200: var(--ig-info-h), calc(var(--ig-info-s) * 0.64), calc(var(--ig-info-l) * 1.43); + --ig-info-300-contrast: black; + --ig-info-300: var(--ig-info-h), calc(var(--ig-info-s) * 0.73), calc(var(--ig-info-l) * 1.19); + --ig-info-400-contrast: black; + --ig-info-400: var(--ig-info-h), calc(var(--ig-info-s) * 0.875), calc(var(--ig-info-l) * 1.08); + --ig-info-h: 209deg; + --ig-info-s: 84%; + --ig-info-l: 45%; + --ig-info-a: 1; + --ig-info-500-contrast: black; + --ig-info-500: var(--ig-info-h), calc(var(--ig-info-s) * 1), calc(var(--ig-info-l) * 1); + --ig-info-600-contrast: white; + --ig-info-600: var(--ig-info-h), calc(var(--ig-info-s) * 1.26), calc(var(--ig-info-l) * 0.89); + --ig-info-700-contrast: white; + --ig-info-700: var(--ig-info-h), calc(var(--ig-info-s) * 1.52), calc(var(--ig-info-l) * 0.81); + --ig-info-800-contrast: white; + --ig-info-800: var(--ig-info-h), calc(var(--ig-info-s) * 1.5), calc(var(--ig-info-l) * 0.73); + --ig-info-900-contrast: white; + --ig-info-900: var(--ig-info-h), calc(var(--ig-info-s) * 1.34), calc(var(--ig-info-l) * 0.64); + --ig-info-A100-contrast: black; + --ig-info-A100: var(--ig-info-h), calc(var(--ig-info-s) * 1.23), calc(var(--ig-info-l) * 1.34); + --ig-info-A200-contrast: black; + --ig-info-A200: var(--ig-info-h), calc(var(--ig-info-s) * 1.22), calc(var(--ig-info-l) * 1.16); + --ig-info-A400-contrast: white; + --ig-info-A400: var(--ig-info-h), calc(var(--ig-info-s) * 1.23), calc(var(--ig-info-l) * 0.91); + --ig-info-A700-contrast: white; + --ig-info-A700: var(--ig-info-h), calc(var(--ig-info-s) * 1.23), calc(var(--ig-info-l) * 0.65); + --ig-success-50-contrast: black; + --ig-success-50: var(--ig-success-h), calc(var(--ig-success-s) * 1.23), calc(var(--ig-success-l) * 1.78); + --ig-success-100-contrast: black; + --ig-success-100: var(--ig-success-h), calc(var(--ig-success-s) * 0.8), calc(var(--ig-success-l) * 1.66); + --ig-success-200-contrast: black; + --ig-success-200: var(--ig-success-h), calc(var(--ig-success-s) * 0.64), calc(var(--ig-success-l) * 1.43); + --ig-success-300-contrast: black; + --ig-success-300: var(--ig-success-h), calc(var(--ig-success-s) * 0.73), calc(var(--ig-success-l) * 1.19); + --ig-success-400-contrast: black; + --ig-success-400: var(--ig-success-h), calc(var(--ig-success-s) * 0.875), calc(var(--ig-success-l) * 1.08); + --ig-success-h: 131deg; + --ig-success-s: 43%; + --ig-success-l: 51%; + --ig-success-a: 1; + --ig-success-500-contrast: black; + --ig-success-500: var(--ig-success-h), calc(var(--ig-success-s) * 1), calc(var(--ig-success-l) * 1); + --ig-success-600-contrast: black; + --ig-success-600: var(--ig-success-h), calc(var(--ig-success-s) * 1.26), calc(var(--ig-success-l) * 0.89); + --ig-success-700-contrast: black; + --ig-success-700: var(--ig-success-h), calc(var(--ig-success-s) * 1.52), calc(var(--ig-success-l) * 0.81); + --ig-success-800-contrast: black; + --ig-success-800: var(--ig-success-h), calc(var(--ig-success-s) * 1.5), calc(var(--ig-success-l) * 0.73); + --ig-success-900-contrast: white; + --ig-success-900: var(--ig-success-h), calc(var(--ig-success-s) * 1.34), calc(var(--ig-success-l) * 0.64); + --ig-success-A100-contrast: black; + --ig-success-A100: var(--ig-success-h), calc(var(--ig-success-s) * 1.23), calc(var(--ig-success-l) * 1.34); + --ig-success-A200-contrast: black; + --ig-success-A200: var(--ig-success-h), calc(var(--ig-success-s) * 1.22), calc(var(--ig-success-l) * 1.16); + --ig-success-A400-contrast: black; + --ig-success-A400: var(--ig-success-h), calc(var(--ig-success-s) * 1.23), calc(var(--ig-success-l) * 0.91); + --ig-success-A700-contrast: white; + --ig-success-A700: var(--ig-success-h), calc(var(--ig-success-s) * 1.23), calc(var(--ig-success-l) * 0.65); + --ig-warn-50-contrast: black; + --ig-warn-50: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.23), calc(var(--ig-warn-l) * 1.78); + --ig-warn-100-contrast: black; + --ig-warn-100: var(--ig-warn-h), calc(var(--ig-warn-s) * 0.8), calc(var(--ig-warn-l) * 1.66); + --ig-warn-200-contrast: black; + --ig-warn-200: var(--ig-warn-h), calc(var(--ig-warn-s) * 0.64), calc(var(--ig-warn-l) * 1.43); + --ig-warn-300-contrast: black; + --ig-warn-300: var(--ig-warn-h), calc(var(--ig-warn-s) * 0.73), calc(var(--ig-warn-l) * 1.19); + --ig-warn-400-contrast: black; + --ig-warn-400: var(--ig-warn-h), calc(var(--ig-warn-s) * 0.875), calc(var(--ig-warn-l) * 1.08); + --ig-warn-h: 37deg; + --ig-warn-s: 96%; + --ig-warn-l: 54%; + --ig-warn-a: 1; + --ig-warn-500-contrast: black; + --ig-warn-500: var(--ig-warn-h), calc(var(--ig-warn-s) * 1), calc(var(--ig-warn-l) * 1); + --ig-warn-600-contrast: black; + --ig-warn-600: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.26), calc(var(--ig-warn-l) * 0.89); + --ig-warn-700-contrast: black; + --ig-warn-700: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.52), calc(var(--ig-warn-l) * 0.81); + --ig-warn-800-contrast: black; + --ig-warn-800: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.5), calc(var(--ig-warn-l) * 0.73); + --ig-warn-900-contrast: black; + --ig-warn-900: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.34), calc(var(--ig-warn-l) * 0.64); + --ig-warn-A100-contrast: black; + --ig-warn-A100: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.23), calc(var(--ig-warn-l) * 1.34); + --ig-warn-A200-contrast: black; + --ig-warn-A200: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.22), calc(var(--ig-warn-l) * 1.16); + --ig-warn-A400-contrast: black; + --ig-warn-A400: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.23), calc(var(--ig-warn-l) * 0.91); + --ig-warn-A700-contrast: black; + --ig-warn-A700: var(--ig-warn-h), calc(var(--ig-warn-s) * 1.23), calc(var(--ig-warn-l) * 0.65); + --ig-error-50-contrast: black; + --ig-error-50: var(--ig-error-h), calc(var(--ig-error-s) * 1.23), calc(var(--ig-error-l) * 1.78); + --ig-error-100-contrast: black; + --ig-error-100: var(--ig-error-h), calc(var(--ig-error-s) * 0.8), calc(var(--ig-error-l) * 1.66); + --ig-error-200-contrast: black; + --ig-error-200: var(--ig-error-h), calc(var(--ig-error-s) * 0.64), calc(var(--ig-error-l) * 1.43); + --ig-error-300-contrast: black; + --ig-error-300: var(--ig-error-h), calc(var(--ig-error-s) * 0.73), calc(var(--ig-error-l) * 1.19); + --ig-error-400-contrast: black; + --ig-error-400: var(--ig-error-h), calc(var(--ig-error-s) * 0.875), calc(var(--ig-error-l) * 1.08); + --ig-error-h: 346deg; + --ig-error-s: 100%; + --ig-error-l: 54%; + --ig-error-a: 1; + --ig-error-500-contrast: black; + --ig-error-500: var(--ig-error-h), calc(var(--ig-error-s) * 1), calc(var(--ig-error-l) * 1); + --ig-error-600-contrast: black; + --ig-error-600: var(--ig-error-h), calc(var(--ig-error-s) * 1.26), calc(var(--ig-error-l) * 0.89); + --ig-error-700-contrast: white; + --ig-error-700: var(--ig-error-h), calc(var(--ig-error-s) * 1.52), calc(var(--ig-error-l) * 0.81); + --ig-error-800-contrast: white; + --ig-error-800: var(--ig-error-h), calc(var(--ig-error-s) * 1.5), calc(var(--ig-error-l) * 0.73); + --ig-error-900-contrast: white; + --ig-error-900: var(--ig-error-h), calc(var(--ig-error-s) * 1.34), calc(var(--ig-error-l) * 0.64); + --ig-error-A100-contrast: black; + --ig-error-A100: var(--ig-error-h), calc(var(--ig-error-s) * 1.23), calc(var(--ig-error-l) * 1.34); + --ig-error-A200-contrast: black; + --ig-error-A200: var(--ig-error-h), calc(var(--ig-error-s) * 1.22), calc(var(--ig-error-l) * 1.16); + --ig-error-A400-contrast: black; + --ig-error-A400: var(--ig-error-h), calc(var(--ig-error-s) * 1.23), calc(var(--ig-error-l) * 0.91); + --ig-error-A700-contrast: white; + --ig-error-A700: var(--ig-error-h), calc(var(--ig-error-s) * 1.23), calc(var(--ig-error-l) * 0.65); +} diff --git a/samples/grids/grid-lite/styling-custom-theme/src/index.tsx b/samples/grids/grid-lite/styling-custom-theme/src/index.tsx new file mode 100644 index 000000000..f5aa47649 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/src/index.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { GridLiteDataService, ProductInfo } from './GridLiteDataService'; + +// Import the web component +import { IgcGridLite } from 'igniteui-grid-lite'; +import { + defineComponents, + IgcRatingComponent +} from 'igniteui-webcomponents'; + +import "igniteui-webcomponents/themes/light/bootstrap.css"; +import "./index.css"; + +// Register components +IgcGridLite.register(); +defineComponents(IgcRatingComponent); + +export default class Sample extends React.Component { + private dataService: GridLiteDataService; + private gridRef: React.RefObject; + + constructor(props: any) { + super(props); + this.dataService = new GridLiteDataService(); + this.gridRef = React.createRef(); + } + + componentDidMount() { + if (this.gridRef.current) { + const data: ProductInfo[] = this.dataService.generateProducts(50); + + const columns = [ + { + key: 'name', + headerText: 'Product', + sort: true, + filter: true + }, + { + key: 'price', + headerText: 'Price', + sort: true, + filter: true, + type: 'number' + }, + { + key: 'sold', + headerText: 'Sold', + sort: true, + filter: true, + type: 'number' + }, + { + key: 'total', + headerText: 'Total', + sort: true, + filter: true, + type: 'number' + }, + { + key: 'rating', + headerText: 'Rating', + type: 'number', + sort: true, + filter: true, + cellTemplate: (params: any) => { + const rating = document.createElement('igc-rating'); + rating.setAttribute('readonly', ''); + rating.setAttribute('value', params.value.toString()); + return rating; + } + } + ]; + + this.gridRef.current.columns = columns; + this.gridRef.current.data = data; + } + } + + public render(): JSX.Element { + return ( +
+
+ +
+
+ ); + } +} + +// rendering above component in the React DOM +const root = ReactDOM.createRoot(document.getElementById('root')); +root.render(); diff --git a/samples/grids/grid-lite/styling-custom-theme/tsconfig.json b/samples/grids/grid-lite/styling-custom-theme/tsconfig.json new file mode 100644 index 000000000..8c0d146f9 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "resolveJsonModule": true, + "esModuleInterop": true, + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "noUnusedLocals": false, + "importHelpers": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": false, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts", + "**/odatajs-4.0.0.js", + "config-overrides.js" + ], + "include": [ + "src" + ] +} diff --git a/samples/grids/grid-lite/styling-custom-theme/vite.config.js b/samples/grids/grid-lite/styling-custom-theme/vite.config.js new file mode 100644 index 000000000..1744dbc71 --- /dev/null +++ b/samples/grids/grid-lite/styling-custom-theme/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'build' + }, + server: { + open: false + }, +}); \ No newline at end of file