Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
d36ea9539a | |||
5a5337dc63 | |||
443081cc28 | |||
ac8503f8c8 | |||
1cc1fd0a5a | |||
34314aa4ca | |||
0d8dcf4829 | |||
47c6d0dd62 | |||
84937e3eec | |||
303e270b56 | |||
bb1ada6e14 | |||
4a422cc796 | |||
be0f244c02 | |||
78a8dc8458 | |||
38062af889 | |||
f2eadf5441 | |||
a42931384f | |||
8116ce697b | |||
4964b86d67 | |||
2b331e7655 | |||
c1468b688e | |||
4f7837c88e | |||
fd8e06f1dd | |||
b01a351eaa | |||
604655c02d | |||
6603ac4389 | |||
cca6f952ee | |||
df94a6322d | |||
73e7f64860 | |||
e17e1650d5 | |||
3ecb63d500 | |||
41ee7e90ef | |||
c70bba727e | |||
747248454d | |||
59386241b4 | |||
c70b9b0dd1 | |||
2ee00ed919 | |||
cbfc271da5 | |||
d45b492837 | |||
ed54c145b7 | |||
64ed9a6044 | |||
75267abd91 | |||
ba9a3992b7 | |||
a74c32ed6d | |||
c5f9812acc | |||
bb0d6853e5 | |||
8c9fe168d8 | |||
6c874c01b7 | |||
5bc84b621c | |||
dd421eedf5 | |||
570d8a73cc |
55
CHANGELOG.md
55
CHANGELOG.md
@ -1,3 +1,58 @@
|
||||
### **4.2.13** (2021-12-08)
|
||||
|
||||
- Fix broken link about how to import fonts #62
|
||||
- Add a video to show how to test the theme in a local container
|
||||
|
||||
### **4.2.12** (2021-12-08)
|
||||
|
||||
- Update post build instructions
|
||||
|
||||
### **4.2.11** (2021-12-07)
|
||||
|
||||
|
||||
|
||||
### **4.2.10** (2021-11-12)
|
||||
|
||||
- Export an exaustive list of KcLanguageTag
|
||||
|
||||
### **4.2.9** (2021-11-11)
|
||||
|
||||
- Fix useAdvancedMsg
|
||||
|
||||
### **4.2.8** (2021-11-10)
|
||||
|
||||
- Update doc about pattern that can be used for user attributes #50
|
||||
- Bring back Safari compat
|
||||
|
||||
### **4.2.7** (2021-11-09)
|
||||
|
||||
- Fix useFormValidationSlice
|
||||
|
||||
### **4.2.6** (2021-11-08)
|
||||
|
||||
- Fix deepClone so we can overwrite with undefined in when we mock kcContext
|
||||
|
||||
### **4.2.5** (2021-11-07)
|
||||
|
||||
- Better debugging experience with user profile
|
||||
|
||||
### **4.2.4** (2021-11-01)
|
||||
|
||||
- Better autoComplete typings
|
||||
|
||||
### **4.2.3** (2021-11-01)
|
||||
|
||||
- Make it more easy to understand that error in the log are expected
|
||||
|
||||
### **4.2.2** (2021-10-27)
|
||||
|
||||
- Replace 'path' by 'browserify-path' #47
|
||||
|
||||
### **4.2.1** (2021-10-26)
|
||||
|
||||
- useFormValidationSlice: update when params have changed
|
||||
- Explains that the password can't be validated
|
||||
|
||||
## **4.2.0** (2021-10-26)
|
||||
|
||||
- Export types definitions for Attribue and Validator
|
||||
|
41
README.md
41
README.md
@ -77,6 +77,7 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak
|
||||
- [Implement context persistence (optional)](#implement-context-persistence-optional)
|
||||
- [Kickstart video](#kickstart-video)
|
||||
- [About the errors related to `objectToJson` in Keycloak logs.](#about-the-errors-related-to-objecttojson-in-keycloak-logs)
|
||||
- [The pages take too long to load ?](#the-pages-take-too-long-to-load-)
|
||||
- [Adding custom message (to `i18n/useKcMessage.tsx`)](#adding-custom-message-to-i18nusekcmessagetsx)
|
||||
- [Email domain whitelist](#email-domain-whitelist)
|
||||
- [Changelog highlights](#changelog-highlights)
|
||||
@ -87,6 +88,8 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak
|
||||
|
||||
# Requirements
|
||||
|
||||
On Windows OS you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). More info [here](https://github.com/InseeFrLab/keycloakify/issues/54%23issuecomment-984834217)
|
||||
|
||||
Tested with the following Keycloak versions:
|
||||
|
||||
- [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore)
|
||||
@ -106,8 +109,6 @@ For more information see [this issue](https://github.com/InseeFrLab/keycloakify/
|
||||
- `mvn` ([Maven](https://maven.apache.org/)), `rm`, `mkdir`, `curl`, `unzip` are assumed to be available.
|
||||
- `docker` must be up and running when running `yarn keycloak`.
|
||||
|
||||
On Windows you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
|
||||
|
||||
## My framework doesn’t seem to be supported, what can I do?
|
||||
|
||||
Currently Keycloakify is only compatible with `create-react-app` apps.
|
||||
@ -307,6 +308,8 @@ Checkout a complete setup [here](https://github.com/garronej/keycloakify-demo-ap
|
||||
</a>
|
||||
</p>
|
||||
|
||||
NOTE: In reality the regexp used in this gif doesn't work server side, the regexp pattern should be `^[^@]@gmail\.com$` 😬.
|
||||
|
||||
User Profile is a Keycloak feature that enables to
|
||||
[define, from the admin console](https://user-images.githubusercontent.com/6702424/136872461-1f5b64ef-d2ef-4c6b-bb8d-07d4729552b3.png),
|
||||
what information you want to collect on your users in the register page and to validate inputs
|
||||
@ -322,6 +325,9 @@ provides frontend validation out of the box.
|
||||
For implementing your own `register-user-profile.ftl` page, you can use [`import { useFormValidationSlice } from "keycloakify";`](https://github.com/InseeFrLab/keycloakify/blob/main/src/lib/useFormValidationSlice.tsx).
|
||||
Find usage example [`here`](https://github.com/InseeFrLab/keycloakify/blob/d3a07edfcb3739e30032dc96fc2a55944dfc3387/src/lib/components/RegisterUserProfile.tsx#L79-L112).
|
||||
|
||||
As for right now [it's not possible to define a pattern for the password](https://keycloak.discourse.group/t/make-password-policies-available-to-freemarker/11632)
|
||||
from the admin console. You can however pass validators for it to the `useFormValidationSlice` function.
|
||||
|
||||
# Support for Terms and conditions
|
||||
|
||||
[Many organizations have a requirement that when a new user logs in for the first time, they need to agree to the terms and conditions of the website.](https://www.keycloak.org/docs/4.8/server_admin/#terms-and-conditions).
|
||||
@ -368,7 +374,8 @@ this limitation doesn't apply, you can import fonts however you see fit.
|
||||
- If it is possible, use Google Fonts or any other font provider.
|
||||
- If you want to host your font recommended approach is to move your fonts into the `public`
|
||||
directory and to place your `@font-face` statements in the `public/index.html`.
|
||||
Example [here](https://github.com/InseeFrLab/onyxia-ui/blob/0e3a04610cfe872ca71dad59e05ced8f785dee4b/public/index.html#L6-L51).
|
||||
Example [here](https://github.com/garronej/keycloakify-demo-app/blob/9aa2dbaec28a7786d6b2983c9a59d393dec1b2d6/public/index.html#L27-L73)
|
||||
(and the font are [here](https://github.com/garronej/keycloakify-demo-app/tree/main/public/fonts/WorkSans)).
|
||||
- You can also [use non relative url](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/src/fonts.scss#L16) but don't forget [`Access-Control-Allow-Origin`](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/nginx.conf#L17-L19).
|
||||
|
||||
# Implement context persistence (optional)
|
||||
@ -441,18 +448,29 @@ The logs of your keycloak server will always show this kind of errors every time
|
||||
|
||||
```log
|
||||
FTL stack trace ("~" means nesting-related):
|
||||
- Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson" at line 70, column 21]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson" at line 36, column 5]
|
||||
- Reached through: @objectToJson object=value depth=(dep... [in template "login.ftl" in macro "objectToJson" at line 81, column 27]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson" at line 36, column 5]
|
||||
- Reached through: @objectToJson object=(.data_model) de... [in template "login.ftl" at line 163, column 43]
|
||||
- Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 70, column 21]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 36, column 5]
|
||||
- Reached through: @objectToJson_please_ignore_errors object=value depth=(dep... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 81, column 27]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 36, column 5]
|
||||
- Reached through: @objectToJson_please_ignore_errors object=(.data_model) de... [in template "login.ftl" at line 163, column 43]
|
||||
```
|
||||
|
||||
Theses are expected and can be safely ignored.
|
||||
Theses are expected to show up in the log.
|
||||
Unfortunately, there is nothing I know of that can be done to avoid them or even mute them.
|
||||
They can be, however, safely ignored.
|
||||
|
||||
To [converts the `.ftl` values into a JavaScript object](https://github.com/InseeFrLab/keycloakify/blob/main/src/bin/build-keycloak-theme/generateFtl/common.ftl)
|
||||
without making assumptions on the `.data_model` we have to do things that throws.
|
||||
It's all-right though because every statement that can fail is inside an `<#attempt><#recorver>` block but it results in errors being printed to the logs.
|
||||
It's all-right because every statement that can fail is inside an `<#attempt><#recorver>` block but it results in errors being printed to the logs.
|
||||
|
||||
# The pages take too long to load ?
|
||||
|
||||
The problem of templates taking a long time to load only happens in the test environment, when you have a console logging all the above-mentioned `.ftl` warnings in real time. Logging all those warnings is what takes time. Once in production page load is way faster.
|
||||
|
||||
If you run the docker container locally we acknowledge that the loading time is getting out of hand.
|
||||
We are [in the process](https://github.com/InseeFrLab/keycloakify/pull/63) of resolving this issue.
|
||||
|
||||
In the meantime we recommend [to run the docker container as a background task](https://youtu.be/F29Z1GaH-jk).
|
||||
|
||||
# Adding custom message (to `i18n/useKcMessage.tsx`)
|
||||
|
||||
@ -462,6 +480,9 @@ This approach is a bit hacky as it doesn't provide type safety but it works.
|
||||
|
||||
# Email domain whitelist
|
||||
|
||||
NOTE: This have been kind of deprecated by [user attribute](#user-profile-and-frontend-form-validation) you could
|
||||
use a pattern [like this one](https://github.com/InseeFrLab/onyxia-web/blob/f1206e0329b3b8d401ca7bffa95ca9c213cb190a/src/app/components/KcApp/kcContext.ts#L106) to whitelist email domains.
|
||||
|
||||
If you want to restrict the emails domain that can register, you can use [this plugin](https://github.com/micedre/keycloak-mail-whitelisting)
|
||||
and `kcRegisterContext["authorizedMailDomains"]` to validate on.
|
||||
|
||||
|
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "4.2.0",
|
||||
"version": "4.2.13",
|
||||
"description": "Keycloak theme generator for Reacts app",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -56,9 +56,9 @@
|
||||
"homepage": "https://github.com/garronej/keycloakify",
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.4.1",
|
||||
"powerhooks": "^0.11.0",
|
||||
"powerhooks": "^0.10.0",
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"tss-react": "^1.1.0"
|
||||
"tss-react": "^1.1.0 || ^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emotion/react": "^11.4.1",
|
||||
@ -72,14 +72,14 @@
|
||||
"properties-parser": "^0.3.1",
|
||||
"react": "^17.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tss-react": "^1.1.0",
|
||||
"tss-react": "^3.0.0",
|
||||
"typescript": "^4.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.5",
|
||||
"evt": "2.0.0-beta.38",
|
||||
"minimal-polyfills": "^2.2.1",
|
||||
"path": "^0.12.7",
|
||||
"path-browserify": "^1.0.1",
|
||||
"react-markdown": "^5.0.3",
|
||||
"scripting-tools": "^0.19.13",
|
||||
"tsafe": "^0.8.1"
|
||||
|
@ -121,11 +121,14 @@ export function main() {
|
||||
"",
|
||||
`👉 $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename))} 👈`,
|
||||
"",
|
||||
'To enable the theme within keycloak log into the admin console ( 👉 http://localhost:8080 username: admin, password: admin 👈), create a realm (called "myrealm" for example),',
|
||||
`go to your realm settings, click on the theme tab then select ${themeName}.`,
|
||||
`More details: https://www.keycloak.org/getting-started/getting-started-docker`,
|
||||
"Once your container is up and running: ",
|
||||
"- Log into the admin console 👉 http://localhost:8080 username: admin, password: admin 👈",
|
||||
'- Create a realm named "myrealm"',
|
||||
'- Create a client with id "myclient" and root url: "https://www.keycloak.org/app/"',
|
||||
`- Select Login Theme: ${themeName} (don't forget to save at the bottom of the page)`,
|
||||
`- Go to 👉 https://www.keycloak.org/app/ 👈 Click "Save" then "Sign in". You should see your login page`,
|
||||
"",
|
||||
"Once your container is up and configured 👉 http://localhost:8080/auth/realms/myrealm/account 👈",
|
||||
"Video demoing this process: https://youtu.be/N3wlBoH4hKg",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>const _=
|
||||
<#macro objectToJson object depth>
|
||||
<#macro objectToJson_please_ignore_errors object depth>
|
||||
<@compress>
|
||||
|
||||
<#local isHash = false>
|
||||
@ -45,7 +45,7 @@
|
||||
<#continue>
|
||||
</#if>
|
||||
|
||||
"${key}": <@objectToJson object=value depth=depth+1/>,
|
||||
"${key}": <@objectToJson_please_ignore_errors object=value depth=depth+1/>,
|
||||
|
||||
</#list>
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
|
||||
<#list object as item>
|
||||
|
||||
<@objectToJson object=item depth=depth+1/>,
|
||||
<@objectToJson_please_ignore_errors object=item depth=depth+1/>,
|
||||
|
||||
</#list>
|
||||
|
||||
@ -194,7 +194,7 @@
|
||||
Object.deepAssign(
|
||||
out,
|
||||
//Removing all the undefined
|
||||
JSON.parse(JSON.stringify(<@objectToJson object=.data_model depth=0 />))
|
||||
JSON.parse(JSON.stringify(<@objectToJson_please_ignore_errors object=.data_model depth=0 />))
|
||||
);
|
||||
|
||||
Object.deepAssign(
|
||||
|
@ -149,15 +149,6 @@ const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange,
|
||||
</div>
|
||||
<div className={cx(props.kcInputWrapperClass)}>
|
||||
<input
|
||||
autoComplete={(() => {
|
||||
switch (attribute.name) {
|
||||
case "password-confirm":
|
||||
case "password":
|
||||
return "new-password";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
})()}
|
||||
type={(() => {
|
||||
switch (attribute.name) {
|
||||
case "password-confirm":
|
||||
@ -174,11 +165,7 @@ const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange,
|
||||
className={cx(props.kcInputClass)}
|
||||
aria-invalid={displayableErrors.length !== 0}
|
||||
disabled={attribute.readOnly}
|
||||
{...(attribute.autocomplete === undefined
|
||||
? {}
|
||||
: {
|
||||
"autoComplete": attribute.autocomplete,
|
||||
})}
|
||||
autoComplete={attribute.autocomplete}
|
||||
onBlur={onBlurFactory(attribute.name)}
|
||||
/>
|
||||
{displayableErrors.length !== 0 && (
|
||||
|
@ -217,10 +217,64 @@ export type Attribute = {
|
||||
groupDisplayHeader?: string;
|
||||
groupDisplayDescription?: string;
|
||||
readOnly: boolean;
|
||||
autocomplete?: string;
|
||||
validators: Validators;
|
||||
annotations: Record<string, string>;
|
||||
groupAnnotations: Record<string, string>;
|
||||
autocomplete?:
|
||||
| "on"
|
||||
| "off"
|
||||
| "name"
|
||||
| "honorific-prefix"
|
||||
| "given-name"
|
||||
| "additional-name"
|
||||
| "family-name"
|
||||
| "honorific-suffix"
|
||||
| "nickname"
|
||||
| "email"
|
||||
| "username"
|
||||
| "new-password"
|
||||
| "current-password"
|
||||
| "one-time-code"
|
||||
| "organization-title"
|
||||
| "organization"
|
||||
| "street-address"
|
||||
| "address-line1"
|
||||
| "address-line2"
|
||||
| "address-line3"
|
||||
| "address-level4"
|
||||
| "address-level3"
|
||||
| "address-level2"
|
||||
| "address-level1"
|
||||
| "country"
|
||||
| "country-name"
|
||||
| "postal-code"
|
||||
| "cc-name"
|
||||
| "cc-given-name"
|
||||
| "cc-additional-name"
|
||||
| "cc-family-name"
|
||||
| "cc-number"
|
||||
| "cc-exp"
|
||||
| "cc-exp-month"
|
||||
| "cc-exp-year"
|
||||
| "cc-csc"
|
||||
| "cc-type"
|
||||
| "transaction-currency"
|
||||
| "transaction-amount"
|
||||
| "language"
|
||||
| "bday"
|
||||
| "bday-day"
|
||||
| "bday-month"
|
||||
| "bday-year"
|
||||
| "sex"
|
||||
| "tel"
|
||||
| "tel-country-code"
|
||||
| "tel-national"
|
||||
| "tel-area-code"
|
||||
| "tel-local"
|
||||
| "tel-extension"
|
||||
| "impp"
|
||||
| "url"
|
||||
| "photo";
|
||||
};
|
||||
|
||||
export type Validators = Partial<{
|
||||
|
@ -1,13 +1,12 @@
|
||||
import type { KcContextBase } from "./KcContextBase";
|
||||
import type { KcContextBase, Attribute } from "./KcContextBase";
|
||||
import { kcContextMocks, kcContextCommonMock } from "./kcContextMocks";
|
||||
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
|
||||
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
|
||||
import type { DeepPartial } from "../tools/DeepPartial";
|
||||
import { deepAssign } from "../tools/deepAssign";
|
||||
|
||||
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
|
||||
? KcContextBase
|
||||
: AndByDiscriminatingKey<"pageId", KcContextExtended & KcContextBase.Common, KcContextBase>;
|
||||
import { id } from "tsafe/id";
|
||||
import { exclude } from "tsafe/exclude";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { ExtendsKcContextBase } from "./getKcContextFromWindow";
|
||||
import { getKcContextFromWindow } from "./getKcContextFromWindow";
|
||||
|
||||
export function getKcContext<KcContextExtended extends { pageId: string } = never>(params?: {
|
||||
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
|
||||
@ -44,12 +43,55 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
|
||||
"target": kcContext,
|
||||
"source": partialKcContextCustomMock,
|
||||
});
|
||||
|
||||
if (partialKcContextCustomMock.pageId === "register-user-profile.ftl") {
|
||||
assert(kcContextDefaultMock?.pageId === "register-user-profile.ftl");
|
||||
|
||||
const { attributes } = kcContextDefaultMock.profile;
|
||||
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes = [];
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName = {};
|
||||
|
||||
const partialAttributes = [
|
||||
...((partialKcContextCustomMock as DeepPartial<KcContextBase.RegisterUserProfile>).profile?.attributes ?? []),
|
||||
].filter(exclude(undefined));
|
||||
|
||||
attributes.forEach(attribute => {
|
||||
const partialAttribute = partialAttributes.find(({ name }) => name === attribute.name);
|
||||
|
||||
const augmentedAttribute: Attribute = {} as any;
|
||||
|
||||
deepAssign({
|
||||
"target": augmentedAttribute,
|
||||
"source": attribute,
|
||||
});
|
||||
|
||||
if (partialAttribute !== undefined) {
|
||||
partialAttributes.splice(partialAttributes.indexOf(partialAttribute), 1);
|
||||
|
||||
deepAssign({
|
||||
"target": augmentedAttribute,
|
||||
"source": partialAttribute,
|
||||
});
|
||||
}
|
||||
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(augmentedAttribute);
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[augmentedAttribute.name] = augmentedAttribute;
|
||||
});
|
||||
|
||||
partialAttributes.forEach(partialAttribute => {
|
||||
const { name } = partialAttribute;
|
||||
|
||||
assert(name !== undefined, "If you define a mock attribute it must have at least a name");
|
||||
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any);
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { kcContext };
|
||||
}
|
||||
|
||||
return {
|
||||
"kcContext": typeof window === "undefined" ? undefined : (window as any)[ftlValuesGlobalName],
|
||||
};
|
||||
return { "kcContext": getKcContextFromWindow<KcContextExtended>() };
|
||||
}
|
||||
|
11
src/lib/getKcContext/getKcContextFromWindow.ts
Normal file
11
src/lib/getKcContext/getKcContextFromWindow.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { KcContextBase } from "./KcContextBase";
|
||||
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
|
||||
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
|
||||
|
||||
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
|
||||
? KcContextBase
|
||||
: AndByDiscriminatingKey<"pageId", KcContextExtended & KcContextBase.Common, KcContextBase>;
|
||||
|
||||
export function getKcContextFromWindow<KcContextExtended extends { pageId: string } = never>(): ExtendsKcContextBase<KcContextExtended> | undefined {
|
||||
return typeof window === "undefined" ? undefined : (window as any)[ftlValuesGlobalName];
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
export type { KcContextBase, Attribute, Validators } from "./KcContextBase";
|
||||
export type { ExtendsKcContextBase } from "./getKcContextFromWindow";
|
||||
export { getKcContext } from "./getKcContext";
|
||||
|
@ -278,29 +278,6 @@ export const kcContextMocks: KcContextBase[] = [
|
||||
"readOnly": false,
|
||||
"name": "lastName",
|
||||
},
|
||||
{
|
||||
"validators": {
|
||||
"length": {
|
||||
"ignore.empty.value": true,
|
||||
"min": "3",
|
||||
"max": "9",
|
||||
},
|
||||
"up-immutable-attribute": {},
|
||||
"up-attribute-required-by-metadata-value": {},
|
||||
"email": {
|
||||
"ignore.empty.value": true,
|
||||
},
|
||||
},
|
||||
"displayName": "${foo}",
|
||||
"annotations": {
|
||||
"this_is_second_key": "this_is_second_value",
|
||||
"this_is_first_key": "this_is_first_value",
|
||||
},
|
||||
"required": true,
|
||||
"groupAnnotations": {},
|
||||
"readOnly": false,
|
||||
"name": "foo",
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
|
@ -34,7 +34,7 @@ export function getKcLanguageTagLabel(language: KcLanguageTag): LanguageLabel {
|
||||
return kcLanguageByTagLabel[language] ?? language;
|
||||
}
|
||||
|
||||
const availableLanguages = objectKeys(kcMessages);
|
||||
export const kcLanguageTags = objectKeys(kcMessages);
|
||||
|
||||
/**
|
||||
* Pass in "fr-FR" or "français" for example, it will return the AvailableLanguage
|
||||
@ -45,7 +45,7 @@ const availableLanguages = objectKeys(kcMessages);
|
||||
export function getBestMatchAmongKcLanguageTag(languageLike: string): KcLanguageTag {
|
||||
const iso2LanguageLike = languageLike.split("-")[0].toLowerCase();
|
||||
|
||||
const kcLanguageTag = availableLanguages.find(
|
||||
const kcLanguageTag = kcLanguageTags.find(
|
||||
language =>
|
||||
language.toLowerCase().includes(iso2LanguageLike) ||
|
||||
getKcLanguageTagLabel(language).toLocaleLowerCase() === languageLike.toLocaleLowerCase(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createUseGlobalState } from "powerhooks/useGlobalState";
|
||||
import { getKcContext } from "../getKcContext";
|
||||
import { getKcContextFromWindow } from "../getKcContext/getKcContextFromWindow";
|
||||
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
|
||||
import type { StatefulEvt } from "powerhooks";
|
||||
import { KcLanguageTag } from "./KcLanguageTag";
|
||||
@ -8,7 +8,7 @@ import { KcLanguageTag } from "./KcLanguageTag";
|
||||
const wrap = createUseGlobalState(
|
||||
"kcLanguageTag",
|
||||
() => {
|
||||
const { kcContext } = getKcContext();
|
||||
const kcContext = getKcContextFromWindow();
|
||||
|
||||
const languageLike = kcContext?.locale?.current ?? (typeof navigator === "undefined" ? undefined : navigator.language);
|
||||
|
||||
|
@ -27,8 +27,9 @@ function resolveMsg<Key extends string, DoRenderMarkdown extends boolean>(props:
|
||||
|
||||
str = (() => {
|
||||
const startIndex = str
|
||||
.match(/(?<={)[0-9]+(?=})/g)
|
||||
?.map(g => parseInt(g))
|
||||
.match(/{[0-9]+}/g)
|
||||
?.map(g => g.match(/{([0-9]+)}/)![1])
|
||||
.map(indexStr => parseInt(indexStr))
|
||||
.sort((a, b) => a - b)[0];
|
||||
|
||||
if (startIndex === undefined) {
|
||||
@ -67,16 +68,16 @@ function resolveMsgAdvanced<Key extends string, DoRenderMarkdown extends boolean
|
||||
|
||||
const match = key.match(/^\$\{([^{]+)\}$/);
|
||||
|
||||
const resolvedKey = match === null ? key : match[1];
|
||||
const keyUnwrappedFromCurlyBraces = match === null ? key : match[1];
|
||||
|
||||
const out = resolveMsg({
|
||||
"key": resolvedKey,
|
||||
"key": keyUnwrappedFromCurlyBraces,
|
||||
args,
|
||||
kcLanguageTag,
|
||||
doRenderMarkdown,
|
||||
});
|
||||
|
||||
return (out !== undefined ? out : match === null ? doRenderMarkdown ? <span>{key}</span> : key : undefined) as any;
|
||||
return (out !== undefined ? out : doRenderMarkdown ? <span>{keyUnwrappedFromCurlyBraces}</span> : keyUnwrappedFromCurlyBraces) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { assert } from "tsafe/assert";
|
||||
import { is } from "tsafe/is";
|
||||
import { deepClone } from "./deepClone";
|
||||
|
||||
//Warning: Be mindful that because of array this is not idempotent.
|
||||
export function deepAssign(params: { target: Record<string, unknown>; source: Record<string, unknown> }) {
|
||||
const { target, source } = params;
|
||||
const { target } = params;
|
||||
|
||||
const source = deepClone(params.source);
|
||||
|
||||
Object.keys(source).forEach(key => {
|
||||
var dereferencedSource = source[key];
|
||||
|
@ -1,3 +1,17 @@
|
||||
export function deepClone<T>(arg: T): T {
|
||||
return JSON.parse(JSON.stringify(arg));
|
||||
import "minimal-polyfills/Object.fromEntries";
|
||||
|
||||
export function deepClone<T>(o: T): T {
|
||||
if (!(o instanceof Object)) {
|
||||
return o;
|
||||
}
|
||||
|
||||
if (typeof o === "function") {
|
||||
return o;
|
||||
}
|
||||
|
||||
if (o instanceof Array) {
|
||||
return o.map(deepClone) as any;
|
||||
}
|
||||
|
||||
return Object.fromEntries(Object.entries(o).map(([key, value]) => [key, deepClone(value)])) as any;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import { useKcMessage } from "./i18n/useKcMessage";
|
||||
import { useConstCallback } from "powerhooks/useConstCallback";
|
||||
import { id } from "tsafe/id";
|
||||
import type { MessageKey } from "./i18n/useKcMessage";
|
||||
import { useConst } from "powerhooks/useConst";
|
||||
import { emailRegexp } from "./tools/emailRegExp";
|
||||
|
||||
export type KcContextLike = {
|
||||
@ -39,8 +38,24 @@ export function useGetErrors(params: {
|
||||
|
||||
const { value: defaultValue, validators } = attributes.find(attribute => attribute.name === name)!;
|
||||
|
||||
if (defaultValue === value && messagesPerField.existsError(value)) {
|
||||
const errorMessageStr = messagesPerField.get(value);
|
||||
block: {
|
||||
if (defaultValue !== value) {
|
||||
break block;
|
||||
}
|
||||
|
||||
let doesErrorExist: boolean;
|
||||
|
||||
try {
|
||||
doesErrorExist = messagesPerField.existsError(name);
|
||||
} catch {
|
||||
break block;
|
||||
}
|
||||
|
||||
if (!doesErrorExist) {
|
||||
break block;
|
||||
}
|
||||
|
||||
const errorMessageStr = messagesPerField.get(name);
|
||||
|
||||
return [
|
||||
{
|
||||
@ -278,6 +293,7 @@ export function useFormValidationSlice(params: {
|
||||
passwordRequired: boolean;
|
||||
realm: { registrationEmailAsUsername: boolean };
|
||||
};
|
||||
/** NOTE: Try to avoid passing a new ref every render for better performances. */
|
||||
passwordValidators?: Validators;
|
||||
}) {
|
||||
const {
|
||||
@ -290,49 +306,53 @@ export function useFormValidationSlice(params: {
|
||||
},
|
||||
} = params;
|
||||
|
||||
const attributesWithPassword = useConst(() =>
|
||||
!kcContext.passwordRequired
|
||||
? kcContext.profile.attributes
|
||||
: (() => {
|
||||
const name = kcContext.realm.registrationEmailAsUsername ? "email" : "username";
|
||||
const attributesWithPassword = useMemo(
|
||||
() =>
|
||||
!kcContext.passwordRequired
|
||||
? kcContext.profile.attributes
|
||||
: (() => {
|
||||
const name = kcContext.realm.registrationEmailAsUsername ? "email" : "username";
|
||||
|
||||
return kcContext.profile.attributes.reduce<Attribute[]>(
|
||||
(prev, curr) => [
|
||||
...prev,
|
||||
...(curr.name !== name
|
||||
? [curr]
|
||||
: [
|
||||
curr,
|
||||
id<Attribute>({
|
||||
"name": "password",
|
||||
"displayName": id<`\${${MessageKey}}`>("${password}"),
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"validators": passwordValidators,
|
||||
"annotations": {},
|
||||
"groupAnnotations": {},
|
||||
}),
|
||||
id<Attribute>({
|
||||
"name": "password-confirm",
|
||||
"displayName": id<`\${${MessageKey}}`>("${passwordConfirm}"),
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"validators": {
|
||||
"_compareToOther": {
|
||||
"name": "password",
|
||||
"ignore.empty.value": true,
|
||||
"shouldBe": "equal",
|
||||
"error-message": id<`\${${MessageKey}}`>("${invalidPasswordConfirmMessage}"),
|
||||
return kcContext.profile.attributes.reduce<Attribute[]>(
|
||||
(prev, curr) => [
|
||||
...prev,
|
||||
...(curr.name !== name
|
||||
? [curr]
|
||||
: [
|
||||
curr,
|
||||
id<Attribute>({
|
||||
"name": "password",
|
||||
"displayName": id<`\${${MessageKey}}`>("${password}"),
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"validators": passwordValidators,
|
||||
"annotations": {},
|
||||
"groupAnnotations": {},
|
||||
"autocomplete": "new-password",
|
||||
}),
|
||||
id<Attribute>({
|
||||
"name": "password-confirm",
|
||||
"displayName": id<`\${${MessageKey}}`>("${passwordConfirm}"),
|
||||
"required": true,
|
||||
"readOnly": false,
|
||||
"validators": {
|
||||
"_compareToOther": {
|
||||
"name": "password",
|
||||
"ignore.empty.value": true,
|
||||
"shouldBe": "equal",
|
||||
"error-message": id<`\${${MessageKey}}`>("${invalidPasswordConfirmMessage}"),
|
||||
},
|
||||
},
|
||||
},
|
||||
"annotations": {},
|
||||
"groupAnnotations": {},
|
||||
}),
|
||||
]),
|
||||
],
|
||||
[],
|
||||
);
|
||||
})(),
|
||||
"annotations": {},
|
||||
"groupAnnotations": {},
|
||||
"autocomplete": "new-password",
|
||||
}),
|
||||
]),
|
||||
],
|
||||
[],
|
||||
);
|
||||
})(),
|
||||
[kcContext, passwordValidators],
|
||||
);
|
||||
|
||||
const { getErrors } = useGetErrors({
|
||||
@ -344,27 +364,29 @@ export function useFormValidationSlice(params: {
|
||||
},
|
||||
});
|
||||
|
||||
const initialInternalState = useConst(() =>
|
||||
Object.fromEntries(
|
||||
attributesWithPassword
|
||||
.map(attribute => ({
|
||||
attribute,
|
||||
"errors": getErrors({
|
||||
"name": attribute.name,
|
||||
"fieldValueByAttributeName": Object.fromEntries(
|
||||
attributesWithPassword.map(({ name, value }) => [name, { "value": value ?? "" }]),
|
||||
),
|
||||
}),
|
||||
}))
|
||||
.map(({ attribute, errors }) => [
|
||||
attribute.name,
|
||||
{
|
||||
"value": attribute.value ?? "",
|
||||
errors,
|
||||
"doDisplayPotentialErrorMessages": errors.length !== 0,
|
||||
},
|
||||
]),
|
||||
),
|
||||
const initialInternalState = useMemo(
|
||||
() =>
|
||||
Object.fromEntries(
|
||||
attributesWithPassword
|
||||
.map(attribute => ({
|
||||
attribute,
|
||||
"errors": getErrors({
|
||||
"name": attribute.name,
|
||||
"fieldValueByAttributeName": Object.fromEntries(
|
||||
attributesWithPassword.map(({ name, value }) => [name, { "value": value ?? "" }]),
|
||||
),
|
||||
}),
|
||||
}))
|
||||
.map(({ attribute, errors }) => [
|
||||
attribute.name,
|
||||
{
|
||||
"value": attribute.value ?? "",
|
||||
errors,
|
||||
"doDisplayPotentialErrorMessages": errors.length !== 0,
|
||||
},
|
||||
]),
|
||||
),
|
||||
[attributesWithPassword],
|
||||
);
|
||||
|
||||
type InternalState = typeof initialInternalState;
|
||||
@ -421,7 +443,7 @@ export function useFormValidationSlice(params: {
|
||||
errors.length === 0 && (value !== "" || !attributesWithPassword.find(attribute => attribute.name === name)!.required),
|
||||
),
|
||||
}),
|
||||
[formValidationInternalState],
|
||||
[formValidationInternalState, attributesWithPassword],
|
||||
);
|
||||
|
||||
return { formValidationState, formValidationReducer, attributesWithPassword };
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getKcContext } from "../../lib/getKcContext";
|
||||
import type { KcContextBase } from "../../lib/getKcContext";
|
||||
import type { ExtendsKcContextBase } from "../../lib/getKcContext/getKcContext";
|
||||
import type { ExtendsKcContextBase } from "../../lib/getKcContext";
|
||||
import { same } from "evt/tools/inDepth";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { Equals } from "tsafe";
|
||||
|
182
yarn.lock
182
yarn.lock
@ -64,7 +64,7 @@
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
hoist-non-react-statics "^3.3.1"
|
||||
|
||||
"@emotion/serialize@^1.0.2":
|
||||
"@emotion/serialize@*", "@emotion/serialize@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965"
|
||||
integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==
|
||||
@ -75,16 +75,6 @@
|
||||
"@emotion/utils" "^1.0.0"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@emotion/server@^11.4.0":
|
||||
version "11.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/server/-/server-11.4.0.tgz#3ae1d74cb31c7d013c3c76e88c0c4439076e9f66"
|
||||
integrity sha512-IHovdWA3V0DokzxLtUNDx4+hQI82zUXqQFcVz/om2t44O0YSc+NHB+qifnyAOoQwt3SXcBTgaSntobwUI9gnfA==
|
||||
dependencies:
|
||||
"@emotion/utils" "^1.0.0"
|
||||
html-tokenize "^2.0.0"
|
||||
multipipe "^1.0.2"
|
||||
through "^2.3.8"
|
||||
|
||||
"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.2.tgz#1d9ffde531714ba28e62dac6a996a8b1089719d0"
|
||||
@ -95,7 +85,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@emotion/utils@^1.0.0":
|
||||
"@emotion/utils@*", "@emotion/utils@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
|
||||
integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
|
||||
@ -220,11 +210,6 @@ braces@^3.0.1:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
buffer-from@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0"
|
||||
integrity sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
@ -452,7 +437,7 @@ domelementtype@^2.0.1, domelementtype@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
|
||||
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
|
||||
|
||||
domhandler@4.2.2, domhandler@^4.0, domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.2.2:
|
||||
domhandler@^4.0, domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f"
|
||||
integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==
|
||||
@ -468,13 +453,6 @@ domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0, domutils@^2.8.0:
|
||||
domelementtype "^2.2.0"
|
||||
domhandler "^4.2.0"
|
||||
|
||||
duplexer2@^0.1.2:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
|
||||
integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=
|
||||
dependencies:
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
@ -665,24 +643,6 @@ hoist-non-react-statics@^3.3.1:
|
||||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
html-dom-parser@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-1.0.2.tgz#bb5ff844f214657d899aa4fb7b0a9e7d15607e96"
|
||||
integrity sha512-Jq4oVkVSn+10ut3fyc2P/Fs1jqTo0l45cP6Q8d2ef/9jfkYwulO0QXmyLI0VUiZrXF4czpGgMEJRa52CQ6Fk8Q==
|
||||
dependencies:
|
||||
domhandler "4.2.2"
|
||||
htmlparser2 "6.1.0"
|
||||
|
||||
html-react-parser@^1.2.7:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-1.4.0.tgz#bf264f38b9fdf4d94e2120f6a39586c15cb81bd0"
|
||||
integrity sha512-v8Kxy+7L90ZFSM690oJWBNRzZWZOQquYPpQt6kDQPzQyZptXgOJ69kHSi7xdqNdm1mOfsDPwF4K9Bo/dS5gRTQ==
|
||||
dependencies:
|
||||
domhandler "4.2.2"
|
||||
html-dom-parser "1.0.2"
|
||||
react-property "2.0.0"
|
||||
style-to-js "1.1.0"
|
||||
|
||||
html-to-react@^1.3.4:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.7.tgz#a58129c1b77c6d4e047a647372bd194e25420b89"
|
||||
@ -693,18 +653,7 @@ html-to-react@^1.3.4:
|
||||
lodash.camelcase "^4.3.0"
|
||||
ramda "^0.27.1"
|
||||
|
||||
html-tokenize@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/html-tokenize/-/html-tokenize-2.0.1.tgz#c3b2ea6e2837d4f8c06693393e9d2a12c960be5f"
|
||||
integrity sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==
|
||||
dependencies:
|
||||
buffer-from "~0.1.1"
|
||||
inherits "~2.0.1"
|
||||
minimist "~1.2.5"
|
||||
readable-stream "~1.0.27-1"
|
||||
through2 "~0.4.1"
|
||||
|
||||
htmlparser2@6.1.0, htmlparser2@^6.1.0:
|
||||
htmlparser2@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
||||
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
|
||||
@ -771,16 +720,6 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
inline-style-parser@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
|
||||
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
|
||||
|
||||
is-alphabetical@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d"
|
||||
@ -1023,11 +962,6 @@ minimatch@^3.0.3, minimatch@^3.0.4:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@~1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
mkdirp@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
@ -1038,14 +972,6 @@ ms@2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
multipipe@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
|
||||
integrity sha1-zBPv2DPJzamfIk+GhGG44aP9k50=
|
||||
dependencies:
|
||||
duplexer2 "^0.1.2"
|
||||
object-assign "^4.1.0"
|
||||
|
||||
next-tick@1, next-tick@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
|
||||
@ -1083,16 +1009,11 @@ nth-check@^2.0.0:
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
|
||||
object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-keys@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336"
|
||||
integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
@ -1174,6 +1095,11 @@ parse5@^6.0.1:
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||
|
||||
path-browserify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
||||
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
|
||||
|
||||
path-exists@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||
@ -1194,14 +1120,6 @@ path-type@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
path@^0.12.7:
|
||||
version "0.12.7"
|
||||
resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
|
||||
integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=
|
||||
dependencies:
|
||||
process "^0.11.1"
|
||||
util "^0.10.3"
|
||||
|
||||
picomatch@^2.2.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
||||
@ -1241,11 +1159,6 @@ process-nextick-args@~2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
process@^0.11.1:
|
||||
version "0.11.10"
|
||||
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
||||
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
||||
|
||||
prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
@ -1288,11 +1201,6 @@ react-markdown@^5.0.3:
|
||||
unist-util-visit "^2.0.0"
|
||||
xtend "^4.0.1"
|
||||
|
||||
react-property@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.0.tgz#2156ba9d85fa4741faf1918b38efc1eae3c6a136"
|
||||
integrity sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==
|
||||
|
||||
react@^17.0.1:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
|
||||
@ -1301,7 +1209,17 @@ react@^17.0.1:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
readable-stream@^2.0.2, readable-stream@~2.3.6:
|
||||
readable-stream@~1.0.31:
|
||||
version "1.0.34"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
|
||||
integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@~2.3.6:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
@ -1314,16 +1232,6 @@ readable-stream@^2.0.2, readable-stream@~2.3.6:
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@~1.0.17, readable-stream@~1.0.27-1, readable-stream@~1.0.31:
|
||||
version "1.0.34"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
|
||||
integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
version "0.13.9"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
@ -1492,20 +1400,6 @@ strip-final-newline@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
||||
|
||||
style-to-js@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.0.tgz#631cbb20fce204019b3aa1fcb5b69d951ceac4ac"
|
||||
integrity sha512-1OqefPDxGrlMwcbfpsTVRyzwdhr4W0uxYQzeA2F1CBc8WG04udg2+ybRnvh3XYL4TdHQrCahLtax2jc8xaE6rA==
|
||||
dependencies:
|
||||
style-to-object "0.3.0"
|
||||
|
||||
style-to-object@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46"
|
||||
integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==
|
||||
dependencies:
|
||||
inline-style-parser "0.1.1"
|
||||
|
||||
stylis@^4.0.3:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240"
|
||||
@ -1540,14 +1434,6 @@ through2@^2.0.1:
|
||||
readable-stream "~2.3.6"
|
||||
xtend "~4.0.1"
|
||||
|
||||
through2@~0.4.1:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b"
|
||||
integrity sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=
|
||||
dependencies:
|
||||
readable-stream "~1.0.17"
|
||||
xtend "~2.1.1"
|
||||
|
||||
through@^2.3.8:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
@ -1593,13 +1479,13 @@ tslib@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
|
||||
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
|
||||
|
||||
tss-react@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-1.1.0.tgz#bbbf12b3d30eb02e1a39ac6dba4ca05a9c6bb674"
|
||||
integrity sha512-0UUQaMCbefyXsHesnScLwmoo6lD5sdAVR1h5dgIvCOFTk0i5A5a68K2B9gm89hQFfIKPl7fzolCsJ+G9RE/vpw==
|
||||
tss-react@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-3.0.0.tgz#b084e1d10d1ea23c925b6a2141c1e91a0c5e9a2d"
|
||||
integrity sha512-aZ/DZEuUvqki/1TKKBM4OmRx6TI5lcaF4BLMo0D8lyT/5S7zRFaAdVfAlsirHcQNgOAdf5IjLUcEbCYWcY6PJw==
|
||||
dependencies:
|
||||
"@emotion/server" "^11.4.0"
|
||||
html-react-parser "^1.2.7"
|
||||
"@emotion/serialize" "*"
|
||||
"@emotion/utils" "*"
|
||||
|
||||
type-fest@^0.21.3:
|
||||
version "0.21.3"
|
||||
@ -1677,13 +1563,6 @@ util-deprecate@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
util@^0.10.3:
|
||||
version "0.10.4"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
|
||||
integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
|
||||
dependencies:
|
||||
inherits "2.0.3"
|
||||
|
||||
vfile-message@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
|
||||
@ -1742,13 +1621,6 @@ xtend@^4.0.1, xtend@~4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
xtend@~2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b"
|
||||
integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os=
|
||||
dependencies:
|
||||
object-keys "~0.4.0"
|
||||
|
||||
y18n@^5.0.5:
|
||||
version "5.0.8"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
|
||||
|
Reference in New Issue
Block a user