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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions .githooks/pre-commit

This file was deleted.

1 change: 0 additions & 1 deletion .githooks/pre-push

This file was deleted.

9 changes: 9 additions & 0 deletions .github/workflows/bundle-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,22 @@ jobs:
- name: Build packages & create reports
run: yarn nx affected -t bundle-size --nxBail

# NOTE: monosize-storage-azure only stores base reports for the default branch (master),
# so compare-reports will fail for PRs targeting other branches.
- name: Skip bundle size comparison notice
if: ${{ github.event.pull_request.base.ref != 'master' }}
run: echo "::warning::Bundle size comparison skipped — monosize-storage-azure only stores base reports for the default branch (master). PR targets '${{ github.event.pull_request.base.ref }}'."

- name: Compare bundle size with base
if: ${{ github.event.pull_request.base.ref == 'master' }}
run: npx monosize compare-reports --branch=${{ github.event.pull_request.base.ref }} --output=markdown --quiet > ./monosize-report.md

- name: Save PR number
if: ${{ github.event.pull_request.base.ref == 'master' }}
run: echo ${{ github.event.number }} > pr.txt

- uses: actions/upload-artifact@v6
if: ${{ github.event.pull_request.base.ref == 'master' }}
with:
name: monosize-report
retention-days: 1
Expand Down
2 changes: 0 additions & 2 deletions .githooks/post-checkout → .husky/post-checkout
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
#!/bin/sh

changedFiles="$(git diff-tree -r --name-only --no-commit-id $1 $2)"
node ./scripts/package-manager/src/notify-on-file-changes.js $changedFiles
2 changes: 0 additions & 2 deletions .githooks/post-merge → .husky/post-merge
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
#!/bin/sh

changedFiles="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
node ./scripts/package-manager/src/notify-on-file-changes.js $changedFiles
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nano-staged
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat(react-skeleton): Add size and shape props to Skeleton component",
"packageName": "@fluentui/react-skeleton",
"email": "v.kozlova13@gmail.com",
"dependentChangeType": "patch"
}
4 changes: 2 additions & 2 deletions lint-staged.config.js → nano-staged.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const nonJsExtensions = [
prettierSupportedFileExtensionsByContext.others,
].flat();

// https://www.npmjs.com/package/lint-staged
// https://github.com/usmanyunusov/nano-staged
module.exports = {
[`**/*.{${nonJsExtensions}}`]: [commands.format],
[`**/*.{${prettierSupportedFileExtensionsByContext.js}}`]: [/* commands.format, */ commands.lint],
[`**/*.{${prettierSupportedFileExtensionsByContext.js}}`]: [commands.format, commands.lint],
};
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"create-package": "yarn nx g @fluentui/workspace-plugin:react-library",
"format": "node scripts/executors/src/format.js",
"generate-version-files": "node -r ./scripts/ts-node/src/register ./scripts/generators/src/generate-version-files",
"postinstall": "yarn patch-package && node ./scripts/package-manager/src/postinstall.js",
"postinstall": "yarn patch-package && husky && node ./scripts/package-manager/src/postinstall.js",
"preinstall": "node ./scripts/package-manager/src/preinstall.js",
"publish:beachball": "beachball publish -b origin/master --access public -y",
"start": "node -r ./scripts/ts-node/src/register ./scripts/executors/src/start",
Expand Down Expand Up @@ -225,6 +225,7 @@
"glob": "7.2.0",
"globals": "13.24.0",
"html-webpack-plugin": "5.6.0",
"husky": "9.1.7",
"ignore-not-found-export-webpack-plugin": "1.0.2",
"imports-loader": "1.2.0",
"jest": "30.2.0",
Expand All @@ -239,7 +240,6 @@
"jsonc-eslint-parser": "2.4.1",
"just-scripts": "1.8.2",
"license-webpack-plugin": "4.0.2",
"lint-staged": "10.2.10",
"loader-utils": "2.0.4",
"lodash": "4.17.21",
"markdown-table": "2.0.0",
Expand All @@ -248,6 +248,7 @@
"monosize": "0.6.3",
"monosize-bundler-webpack": "0.1.6",
"monosize-storage-azure": "0.0.16",
"nano-staged": "0.9.0",
"node-plop": "0.25.0",
"nx": "21.6.10",
"p-queue": "6.6.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export interface SkeletonContextValue {
animation?: 'wave' | 'pulse';
// (undocumented)
appearance?: 'opaque' | 'translucent';
// (undocumented)
shape?: 'circle' | 'square' | 'rectangle';
// (undocumented)
size?: SkeletonItemSize;
}

// @public (undocumented)
Expand All @@ -42,11 +46,9 @@ export const SkeletonItem: ForwardRefComponent<SkeletonItemProps>;
export const skeletonItemClassNames: SlotClassNames<SkeletonItemSlots>;

// @public
export type SkeletonItemProps = ComponentProps<SkeletonItemSlots> & {
export type SkeletonItemProps = ComponentProps<SkeletonItemSlots> & Pick<SkeletonProps, 'size' | 'shape'> & {
animation?: 'wave' | 'pulse';
appearance?: 'opaque' | 'translucent';
size?: SkeletonItemSize;
shape?: 'circle' | 'square' | 'rectangle';
};

// @public (undocumented)
Expand All @@ -62,6 +64,8 @@ export type SkeletonProps = Omit<ComponentProps<Partial<SkeletonSlots>>, 'width'
animation?: 'wave' | 'pulse';
appearance?: 'opaque' | 'translucent';
width?: number | string;
size?: SkeletonItemSize;
shape?: 'circle' | 'square' | 'rectangle';
};

// @public (undocumented)
Expand All @@ -70,7 +74,7 @@ export type SkeletonSlots = {
};

// @public
export type SkeletonState = ComponentState<SkeletonSlots> & Required<Pick<SkeletonProps, 'animation' | 'appearance'>>;
export type SkeletonState = ComponentState<SkeletonSlots> & Required<Pick<SkeletonProps, 'animation' | 'appearance'>> & Pick<SkeletonProps, 'size' | 'shape'>;

// @public
export const useSkeleton_unstable: (props: SkeletonProps, ref: React_2.Ref<HTMLElement>) => SkeletonState;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
export type { SkeletonContextValues, SkeletonProps, SkeletonSlots, SkeletonState } from './components/Skeleton/index';
export type {
SkeletonContextValues,
SkeletonItemSize,
SkeletonProps,
SkeletonSlots,
SkeletonState,
} from './components/Skeleton/index';
export {
Skeleton,
renderSkeleton_unstable,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
export type {
SkeletonItemProps,
SkeletonItemSize,
SkeletonItemSlots,
SkeletonItemState,
} from './components/SkeletonItem/index';
export type { SkeletonItemProps, SkeletonItemSlots, SkeletonItemState } from './components/SkeletonItem/index';
export {
SkeletonItem,
renderSkeletonItem_unstable,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { Skeleton } from './Skeleton';
import { useSkeletonItem_unstable } from '../SkeletonItem/useSkeletonItem';
import { SkeletonContextProvider } from '../../contexts/SkeletonContext';
import { isConformant } from '../../testing/isConformant';

describe('Skeleton', () => {
Expand All @@ -23,4 +26,32 @@ describe('Skeleton', () => {
const result = render(<Skeleton />);
expect(result.getByRole('progressbar').getAttribute('aria-busy')).toBeDefined();
});
it('passes size prop to SkeletonItem via context', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<SkeletonContextProvider value={{ size: 24 }}>{children}</SkeletonContextProvider>
);
const { result } = renderHook(() => useSkeletonItem_unstable({}, React.createRef()), { wrapper });
expect(result.current.size).toBe(24);
});
it('passes shape prop to SkeletonItem via context', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<SkeletonContextProvider value={{ shape: 'circle' }}>{children}</SkeletonContextProvider>
);
const { result } = renderHook(() => useSkeletonItem_unstable({}, React.createRef()), { wrapper });
expect(result.current.shape).toBe('circle');
});
it('allows SkeletonItem to override Skeleton size prop', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<SkeletonContextProvider value={{ size: 24 }}>{children}</SkeletonContextProvider>
);
const { result } = renderHook(() => useSkeletonItem_unstable({ size: 48 }, React.createRef()), { wrapper });
expect(result.current.size).toBe(48);
});
it('allows SkeletonItem to override Skeleton shape prop', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<SkeletonContextProvider value={{ shape: 'circle' }}>{children}</SkeletonContextProvider>
);
const { result } = renderHook(() => useSkeletonItem_unstable({ shape: 'square' }, React.createRef()), { wrapper });
expect(result.current.shape).toBe('square');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ export type SkeletonSlots = {
root: NonNullable<Slot<'div', 'span'>>;
};

/**
* Sizes for the SkeletonItem
*/
export type SkeletonItemSize = 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 48 | 56 | 64 | 72 | 96 | 120 | 128;

/**
* Skeleton Props
*/
Expand All @@ -31,6 +36,19 @@ export type SkeletonProps = Omit<ComponentProps<Partial<SkeletonSlots>>, 'width'
* @deprecated Use `className` prop to set width
*/
width?: number | string;

/**
* Sets the size of the SkeletonItems inside the Skeleton in pixels.
* Size is restricted to a limited set of values recommended for most uses (see SkeletonItemSize).
* This value can be overridden by the individual SkeletonItem's `size` prop.
*/
size?: SkeletonItemSize;

/**
* Sets the shape of the SkeletonItems inside the Skeleton.
* This value can be overridden by the individual SkeletonItem's `shape` prop.
*/
shape?: 'circle' | 'square' | 'rectangle';
};

export type SkeletonContextValues = {
Expand All @@ -40,4 +58,6 @@ export type SkeletonContextValues = {
/**
* State used in rendering Skeleton
*/
export type SkeletonState = ComponentState<SkeletonSlots> & Required<Pick<SkeletonProps, 'animation' | 'appearance'>>;
export type SkeletonState = ComponentState<SkeletonSlots> &
Required<Pick<SkeletonProps, 'animation' | 'appearance'>> &
Pick<SkeletonProps, 'size' | 'shape'>;
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { Skeleton } from './Skeleton';
export type { SkeletonContextValues, SkeletonProps, SkeletonSlots, SkeletonState } from './Skeleton.types';
export type {
SkeletonContextValues,
SkeletonItemSize,
SkeletonProps,
SkeletonSlots,
SkeletonState,
} from './Skeleton.types';
export { renderSkeleton_unstable } from './renderSkeleton';
export { useSkeleton_unstable } from './useSkeleton';
export { useSkeletonContextValues } from './useSkeletonContextValues';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useSkeletonContext } from '../../contexts/SkeletonContext';
*/
export const useSkeleton_unstable = (props: SkeletonProps, ref: React.Ref<HTMLElement>): SkeletonState => {
const { animation: contextAnimation, appearance: contextAppearance } = useSkeletonContext();
const { animation = contextAnimation ?? 'wave', appearance = contextAppearance ?? 'opaque' } = props;
const { animation = contextAnimation ?? 'wave', appearance = contextAppearance ?? 'opaque', size, shape } = props;

const root = slot.always(
getIntrinsicElementProps('div', {
Expand All @@ -30,5 +30,5 @@ export const useSkeleton_unstable = (props: SkeletonProps, ref: React.Ref<HTMLEl
}),
{ elementType: 'div' },
);
return { animation, appearance, components: { root: 'div' }, root };
return { animation, appearance, size, shape, components: { root: 'div' }, root };
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import * as React from 'react';
import type { SkeletonContextValues, SkeletonState } from '../Skeleton';

export const useSkeletonContextValues = (state: SkeletonState): SkeletonContextValues => {
const { animation, appearance } = state;
const { animation, appearance, size, shape } = state;

const skeletonGroup = React.useMemo(
() => ({
animation,
appearance,
size,
shape,
}),
[animation, appearance],
[animation, appearance, size, shape],
);

return { skeletonGroup };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import type { SkeletonProps } from '../Skeleton/Skeleton.types';

export type SkeletonItemSlots = {
root: Slot<'div', 'span'>;
};

/**
* Sizes for the SkeletonItem
*/
export type SkeletonItemSize = 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 48 | 56 | 64 | 72 | 96 | 120 | 128;

/**
* SkeletonItem Props
*/
export type SkeletonItemProps = ComponentProps<SkeletonItemSlots> & {
/**
* Sets the animation of the SkeletonItem
* @default wave
*/
animation?: 'wave' | 'pulse';
export type SkeletonItemProps = ComponentProps<SkeletonItemSlots> &
Pick<SkeletonProps, 'size' | 'shape'> & {
/**
* Sets the animation of the SkeletonItem
* @default wave
*/
animation?: 'wave' | 'pulse';

/**
* Sets the appearance of the SkeletonItem
* @default opaque
*/
appearance?: 'opaque' | 'translucent';

/**
* Sets the size of the SkeletonItem in pixels.
* Size is restricted to a limited set of values recommended for most uses(see SkeletonItemSize).
* To set a non-supported size, set `width` and `height` to override the rendered size.
* @default 16
*/
size?: SkeletonItemSize;

/**
* Sets the shape of the SkeletonItem.
* @default rectangle
*/
shape?: 'circle' | 'square' | 'rectangle';
};
/**
* Sets the appearance of the SkeletonItem
* @default opaque
*/
appearance?: 'opaque' | 'translucent';
};

/**
* State used in rendering SkeletonItem
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { SkeletonItem } from './SkeletonItem';
export type { SkeletonItemProps, SkeletonItemSize, SkeletonItemSlots, SkeletonItemState } from './SkeletonItem.types';
export type { SkeletonItemProps, SkeletonItemSlots, SkeletonItemState } from './SkeletonItem.types';
export { renderSkeletonItem_unstable } from './renderSkeletonItem';
export { useSkeletonItem_unstable } from './useSkeletonItem';
export { skeletonItemClassNames, useSkeletonItemStyles_unstable } from './useSkeletonItemStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ import type { SkeletonItemProps, SkeletonItemState } from './SkeletonItem.types'
* @param ref - reference to root HTMLElement of SkeletonItem
*/
export const useSkeletonItem_unstable = (props: SkeletonItemProps, ref: React.Ref<HTMLElement>): SkeletonItemState => {
const { animation: contextAnimation, appearance: contextAppearance } = useSkeletonContext();
const {
animation: contextAnimation,
appearance: contextAppearance,
size: contextSize,
shape: contextShape,
} = useSkeletonContext();
const {
animation = contextAnimation ?? 'wave',
appearance = contextAppearance ?? 'opaque',
size = 16,
shape = 'rectangle',
size = contextSize ?? 16,
shape = contextShape ?? 'rectangle',
} = props;

const root = slot.always(
Expand Down
Loading
Loading